代码之家  ›  专栏  ›  技术社区  ›  rampion

我的打字签名有什么问题?

  •  4
  • rampion  · 技术社区  · 14 年前

    我正在玩弄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的定义迫使 签字人: nodes edges 保持一致 ?

    1 回复  |  直到 14 年前
        1
  •  6
  •   C. A. McCann Ravikant Cherukuri    14 年前

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

    你猜对了;另一个 a 是一个新类型变量。这意味着,它不仅不一样 如在 mkGraph 的签名,是全新的 普遍量化 类型变量,不正确。调用的类型 因此,在您的内部签名既不是多态的,也不是单一的已知类型。不,它“不应该”,按照哈斯克尔的标准。在Haskell98中,实际上不可能为 nodes edges 在你的代码中。是的,有点傻。

    然而,GHC提供了 ScopedTypeVariables extension 这就允许了这一点。GHC用户指南的相关章节还讨论了上述“不可能的类型签名”问题。

    注意,您还需要添加一个显式 forall 在的类型签名中 mkgraph图 ,即, forall a. (Ord a) => [(a,a)] -> Graph a 使类型变量进入范围。启用扩展并添加 福尔 让您的代码类型为我检查。

    推荐文章