haskell - 如何将函数应用于 haskell 构造函数内的值?

标签 haskell

我的构造函数定义为

data MuOp = N  (Name, Name)
          | QN (QName, QName)
          | QO (QOp, QOp)
          | E  (Exp, Exp)
          | D  (Decl, Decl)
          | L  (Literal, Literal)
          | G  (GuardedRhs, GuardedRhs)

我对元组进行了一些操作,例如

same :: MuOp -> Bool
same (N (a,b)) = a == b
same (QN (a,b)) = a == b
same (QO (a,b)) = a == b
same (E (a,b)) = a == b
same (D (a,b)) = a == b
same (L (a,b)) = a == b
same (G (a,b)) = a == b

然而,对多个函数重复它看起来很难看。有没有办法定义一些函数,例如 apply where

apply :: ((a,a) -> c) -> MuOp -> c
apply f (N (a,b)) = f (a, b)
apply f (QN (a,b)) = f (a, b)
apply f (QO (a,b)) = f (a, b)
apply f (E (a,b)) = f (a, b)
apply f (D (a,b)) = f (a, b)
apply f (L (a,b)) = f (a, b)
apply f (G (a,b)) = f (a, b)

所以我可以说 same = apply (\(a,b) -> a == b)fEq c -> apply (\(a,b) -> a == c)

我当前的定义会产生此错误。

Couldn't match expected type ‘a’ with actual type ‘Name’
  ‘a’ is a rigid type variable bound by
      the type signature for apply :: ((a, b) -> c) -> MuOp -> c
      at src/Test/MuCheck/MuOp.hs:28:10
Relevant bindings include
  f :: (a, b) -> c (bound at src/Test/MuCheck/MuOp.hs:29:7)
  apply :: ((a, b) -> c) -> MuOp -> c
    (bound at src/Test/MuCheck/MuOp.hs:29:1)
In the expression: a
In the first argument of ‘f’, namely ‘(a, b)’

最佳答案

仔细考虑一下 apply 的定义:在每种情况下,所有 b 变量的类型都相同吗?请记住,虽然 apply 是一个多态函数,但调用者可以决定类型变量 a 是什么(也称为错误消息中的“刚性类型变量”) .

例如,看这两个案例:

apply :: ((a, a) -> c) -> MuOp -> c
apply f (N  (a, b)) = f (a, b)
apply f (QN (a, b)) = f (a, b)
...

第一行ab都是Name类型,但第二行ab 都是 QName 类型。由于调用者可以决定类型变量a是什么,因此您实际上无法在NameQName<之间进行选择 任意。

解决方案是使用 2 级类型:

{-# Language Rank2Types #-}

apply :: (forall a . Eq a => (a, a) -> c) -> MuOp -> c
apply f (N  (a, b)) = f (a, b)
apply f (QN (a, b)) = f (a, b)
...

之前的隐式量词forall a .已变得显式并被插入函数箭头的左侧。 (此外,还添加了 Eq 约束,但这只是一个小细节。)通过这样做,您允许被调用者(即 apply ) 以使用满足 Eq 约束的任何类型来实例化类型变量 a

关于haskell - 如何将函数应用于 haskell 构造函数内的值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27748744/

相关文章:

haskell - 新类型派生 Monad 错误

haskell - 我如何确定哪些导入来自 Haskell?

haskell - GHCi 和编译的代码似乎表现不同

haskell - 如何重写语法来消除移位归约冲突(在 Haskell Happy 解析器中)

haskell - Haskell中由常量参数化的数据类型

ruby - 这是什么镜头组合器?

haskell - fix 函数是替代 while 循环的更好方法吗?

haskell - 同一事件多次发生

haskell - 如何在 Haskell (GHC) 中启用死代码警告

json - 使用 Aeson 的 `genericToJSON` 将产品类型编码为对象,而不是列表