我的类型签名有什么问题?

时间:2010-11-08 16:18:08

标签: haskell type-signature

我正在使用corecursive数据结构,并且在我的代码中很早就出现了类型错误:

module Graph where
import Data.Map 

data Node a = Node { getLabel :: a, getInEdges :: [Edge a], getOutEdges :: [Edge a] }
data Edge a = Edge { getStart :: Node a, getEnd :: Node a }
data Graph a = Graph { getNodes :: [Node a], getEdges :: [Edge a] }

mkGraph :: (Ord a) => [(a,a)] -> Graph a
mkGraph pairs = Graph (elems nodes) edges
  where nodes :: Map a (Node a)
        edges :: [Edge a]
        (nodes, edges) = foldr addEdge (empty,[]) pairs
        addEdge :: (a,a) -> (Map a (Node a), [Edge a]) -> (Map a (Node a), [Edge a])
        addEdge (startLabel, endLabel) = undefined

当我尝试在ghci中加载时,我得到了

graph.hs:13:25:
    Couldn't match expected type `forall a. Map a (Node a)'
           against inferred type `Map a (Node a)'
      Expected type: (forall a1. Map a1 (Node a1), forall a1. [Edge a1])
      Inferred type: (Map a (Node a), [Edge a])
    In the expression: foldr addEdge (empty, []) pairs
    In a pattern binding:
        (nodes, edges) = foldr addEdge (empty, []) pairs

如果我删除了类型签名nodes :: Map a (Node a)edges :: [Edge a],则错误就会消失。

我在这里做错了什么?我猜测类型变量a不受mkGraph类型签名的约束,但不应该 mkGraph的定义强制anodes的签名中的edgesa相同?

1 个答案:

答案 0 :(得分:6)

  

我在这里做错了什么?我猜测类型变量a不受mkGraph类型签名的约束,但是mkGraph的定义是否应该强制节点和边缘的签名中的a是相同的?

你猜对了;另一个a是一个新的类型变量。这意味着,它不仅与a签名中的mkGraph不同,而且是一个全新的普遍量化的类型变量,这是不正确的。因此,内部签名中称为a的类型既不是多态的,也不是单一已知类型。不,根据Haskell标准,它“不应该”。在Haskell 98中,实际上不可能在代码中为nodesedges编写类型签名。是的,那有点傻。

然而,GHC提供ScopedTypeVariables extension允许此等内容。 GHC用户指南的相关部分还讨论了上述“不可能的类型签名”问题。

请注意,您还需要在forall的类型签名中添加显式mkGraph,即forall a. (Ord a) => [(a,a)] -> Graph a,以便将类型变量纳入范围。启用扩展程序并添加forall可让我检查代码类型。