Haskell推断/显式绑定的类型

时间:2015-02-26 23:42:57

标签: haskell types

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

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]

它仍然表示在应用于Graph a时,它会期待Graph b而不是g2。当然,这是

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

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

2 个答案:

答案 0 :(得分:6)

这是由可怕的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

如果您不想禁用monomorhism限制,可以为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声明多态。

答案 1 :(得分:2)

因为你在方程的右边而不是左边给出了一个类型声明,所以Haskell仍然使用类型推断来计算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