多态函数在Haskell中作为参数 [英] Polymorphic functions as parameters in Haskell
问题描述
我有一个带有两个构造函数的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
但是编译器通知我,它不能将wrap
的第二个定义中的类型变量n
与类型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). /p>
如果相反,我删除了类型签名,则第一个定义会导致它推断出(Integer -> Integer) -> X -> X
类型用于换行,这(预期)会导致第二个定义无法进行检查.
这似乎是一个简单的问题,我必须错过一些显而易见的东西.预先感谢您的帮助和耐心!
由于@ 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
一切都很好.谢谢!
I have an ADT with two constructors; one that wraps a Double
and one that wraps an Integer
. I would like to create a function that takes a unary function on the Num
typeclass and returns a function that applies that unary function to the contents of my ADT.
I've tried this:
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
But the compiler informs me that it can't match the type variable n
to the type Double
in the second definition of 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)
If I remove the second definition (so I only define wrap
on the integer constructor Y
), I get the same error, but on the first definition instead (and with actual type 'Integer'
instead of double).
If instead I remove the type signature, the first definition causes it to infer the type (Integer -> Integer) -> X -> X
for wrap, which (expectedly) causes the second definition to fail to type check.
This seems like such a simple problem that I must be missing something glaringly obvious. Thanks in advance for your help and patience!
Thanks to @user1937198, I figured out that the implicit qualification of n
was happening in the wrong scope; I was saying that I wanted to take a function that took any type that satisfied Num
and mapped that type onto the same type, when what I wanted to say was I needed a function that took all types that satisfied Num
. With RankNTypes
the code becomes:
{-# 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
and all is good again. Thanks!
这篇关于多态函数在Haskell中作为参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!