多态函数在Haskell中作为参数 [英] Polymorphic functions as parameters in Haskell

查看:64
本文介绍了多态函数在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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆