我正在使用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的定义强制a
和nodes
的签名中的edges
与a
相同?
答案 0 :(得分:6)
我在这里做错了什么?我猜测类型变量a不受mkGraph类型签名的约束,但是mkGraph的定义是否应该强制节点和边缘的签名中的a是相同的?
你猜对了;另一个a
是一个新的类型变量。这意味着,它不仅与a
签名中的mkGraph
不同,而且是一个全新的普遍量化的类型变量,这是不正确的。因此,内部签名中称为a
的类型既不是多态的,也不是单一已知类型。不,根据Haskell标准,它“不应该”。在Haskell 98中,实际上不可能在代码中为nodes
和edges
编写类型签名。是的,那有点傻。
然而,GHC提供ScopedTypeVariables
extension允许此等内容。 GHC用户指南的相关部分还讨论了上述“不可能的类型签名”问题。
请注意,您还需要在forall
的类型签名中添加显式mkGraph
,即forall a. (Ord a) => [(a,a)] -> Graph a
,以便将类型变量纳入范围。启用扩展程序并添加forall
可让我检查代码类型。