Haskell Inferred/Explicit Where 绑定的类型

Haskell Inferred/Explicit Types of Where Bindings

我正在尝试编写一个函数来比较两个给定图中节点的度数列表以进行同构的充分性测试,但我注意到以下代码抛出与 [=15= 的类型相关的错误]:

import Data.List

degreeNumbers :: (Eq a) => Graph a -> [Int]
degreeNumbers g = ...

isoByDegree :: (Eq a, Eq b) => Graph a -> Graph b -> Bool
isoByDegree g1 g2 = degs g1 == degs g2
        where degs = sort . degreeNumbers

即使我尝试使用

这样的显式声明来绑定 degs
where degs = (sort . degreeNumbers) :: (Eq c) => Graph c -> [Int]

它仍然说它在应用于 g2 时期待 Graph a 而不是 Graph b 的类型。当然,还有

的简单解决方案
isoByDegree g1 g2 = (sort . degreeNumbers) g1 == (sort . degreeNumbers) g2

但我想知道绑定方法出了什么问题。

这是由可怕的 monomorphism restriction 引起的。使用 NoMonomorphismRestriction.

禁用它
{-# LANGUAGE NoMonomorphismRestriction #-}

import Data.List

type Graph a = [a]

degreeNumbers :: (Eq a) => Graph a -> [Int]
degreeNumbers g = undefined

isoByDegree :: (Eq a, Eq b) => Graph a -> Graph b -> Bool
isoByDegree g1 g2 = degs g1 == degs g2
        where degs = sort . degreeNumbers

如果您不想禁用单态限制,您可以为 degs 的声明提供显式签名。

isoByDegree :: (Eq a, Eq b) => Graph a -> Graph b -> Bool
isoByDegree g1 g2 = degs g1 == degs g2
        where
            degs :: (Eq c) => Graph c -> [Int]
            degs = sort . degreeNumbers

在声明的右侧添加一个签名只会给右侧的表达式一个显式类型(这与推断的类型相同);它不会使 degs 声明多态。

因为你在等式的右边而不是左边给出类型声明,Haskell 仍然使用类型推断来计算 degs 的类型。并且由于单态限制,它只会为不 "look" 像函数的东西推断单态类型。解决方法是显式注释您正在命名的事物,而不是您为其名称赋予的值:

isoByDegree :: (Eq a, Eq b) => Graph a -> Graph b -> Bool
isoByDegree g1 g2 = degs g1 == degs g2
  where degs :: (Eq c) => Graph c -> [Int]
        degs = sort . degreeNumbers