【问题标题】:Polymorphic functions as parameters in Haskell多态函数作为 Haskell 中的参数
【发布时间】:2017-04-14 00:11:28
【问题描述】:

我有一个带有两个构造函数的 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

但是编译器告诉我它无法将类型变量nwrap的第二个定义中的类型Double匹配:

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)

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

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

这似乎是一个如此简单的问题,我一定错过了一些明显的东西。提前感谢您的帮助和耐心等待!

【问题讨论】:

  • Num n => (n -> n) 意味着您的函数将与任何将具体类型转换为具体类型的函数一起使用,只要该类型是 Num 的实例。这并不意味着它需要一个可以处理任何 Num 实例的函数。我不确定如何在 haskell 类型系统中表达这一点。
  • 啊!这正是我需要的线索,谢谢。现在写答案...
  • 您只需更改wrap :: (forall n. Num n => n -> n) -> X -> X

标签: haskell types


【解决方案1】:

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

{-# LANGUAGE RankNTypes #-}
data X = Y Integer
       | Z Double
wrap :: (forall n. Num n => n -> n) -> X -> X
wrap f (Y i) = Y $ f i
wrap f (Z i) = Z $ f i

一切都好起来了。谢谢!

【讨论】:

    猜你喜欢
    • 2018-01-14
    • 1970-01-01
    • 2020-09-19
    • 2013-08-20
    • 2015-01-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多