多态函数作为Haskell中的参数

时间:2017-04-14 00:11:28

标签: haskell types

我有一个带有两个构造函数的ADT;一个包裹Double的一个包裹Integer的一个。我想创建一个函数,它在Num类型类上获取一元函数,并返回一个将该一元函数应用于我的ADT内容的函数。

我试过这个:

data X = Y Integer
       | Z Double
wrap :: Num n => (n -> n) -> X -> X
wrap f (Y i) = Y $ f i
wrap f (Z i) = Z $ f i

但是编译器告诉我,它不能将类型变量nDouble的第二个定义中的wrap类型匹配:

test.hs:5:22: error:
    • Couldn't match expected type ‘n’ with actual type ‘Double’
      ‘n’ is a rigid type variable bound by
        the type signature for:
          wrap :: forall n. Num n => (n -> n) -> X -> X
        at test.hs:3:9
    • In the first argument of ‘f’, namely ‘i’
      In the second argument of ‘($)’, namely ‘f i’
      In the expression: Z $ f i
    • Relevant bindings include
        f :: n -> n (bound at test.hs:5:6)
        wrap :: (n -> n) -> X -> X (bound at test.hs:4:1)

如果我删除第二个定义(所以我只在整数构造函数wrap上定义Y),我会得到相同的错误,但是在第一个定义上(而actual type 'Integer'而不是双倍。)

如果我删除了类型签名,第一个定义会导致它推断包裹的类型(Integer -> Integer) -> X -> X,这(预期)会导致第二个定义无法进行类型检查。

这似乎是一个简单的问题,我必须忽略一些明显的东西。提前感谢您的帮助和耐心!

1 个答案:

答案 0 :(得分:4)

感谢@ user1937198,我发现n的隐式限定发生在错误的范围内;我说我想采用一个满足Num的任何类型的函数,并将该类型映射到同一类型,当我想说的是我需要一个满足所有类型{{1 }}。使用Num,代码变为:

RankNTypes

一切都很好。谢谢!