代码之家  ›  专栏  ›  技术社区  ›  Tim Robinson

不明确的类型变量

  •  3
  • Tim Robinson  · 技术社区  · 14 年前

    有关 my earlier question on traversing data structures ,当我将代码与uniplate包一起使用时,使其成为通用代码时遇到问题。我正在处理 Language.Exts.Annotated.Syntax 模块,它们都是带有类型参数的泛型 l .这个 L 整个树都是一样的。

    我写的代码是这样的:

    doInt :: Child1 l -> Child1 l
    doInt (Child1 l n) = Child1 l (n + 1)
    
    doString :: Child2 l -> Child2 l
    doString (Child2 l (_:s)) = Child2 l ('j' : s)
    
    replace :: Data l => Parent l -> Parent l
    replace = transformBi doInt
            . transformBi doString
    

    此代码会在最后两行中产生以下错误:

    Ambiguous type variable `l' in the constraint:
      `Data l' arising from a use of `transformBi' at Test.hs:31:10-52
    Probable fix: add a type signature that fixes these type variable(s)
    

    我可以理解为什么这个代码是模棱两可的: transformBi 接受一 (to -> to) from 把它变成 在我的例子中 L 在里面 Child1 l 以及 L 在里面 Parent l . 我不知道怎么修。我尝试添加一个类型约束,比如 transformBi (doInt :: Child1 l -> Child1 l) 但我也有同样的错误,好像我在介绍一个新的 L 当我这样做的时候。

    如何告诉编译器我使用的是相同的 L 对于 replace ,请 transformBi doInt transformBi doString ?

    编辑: Here is the full program that demonstrates what I'm doing .根据GHC 6.10.4,该程序无法编译,出现上述错误。

    2 回复  |  直到 14 年前
        1
  •  9
  •   Alexey Romanov    14 年前

    看起来你需要 scoped type variables 延伸。

    {-# LANGUAGE ScopedTypeVariables #-}
    
    replace :: forall l. Data l => Parent l -> Parent l
    replace = transformBi (doInt :: Child1 l -> Child1 l)
            . transformBi (doString :: Child2 l -> Child2 l)
    

    注意量化 必须 明确提出 l 进入范围。

        2
  •  0
  •   Vasiliy Stavenko    14 年前

    l 函数中的类型应相同 replace : 定义如下:

    data L = LInt Integer| LString String
    

    看, 代替 不能是多态函数。它使用严格的类型。此类型由操作定义:

    Prelude> :t (+)
    (+) :: (Num a) => a -> a -> a
    

    Prelude> :t (:)
    (:) :: a -> [a] -> [a]
    

    Prelude> :t 'c'
    'c' :: Char
    

    要使替换多态性,必须使其具有多态功能。