Haskell 和函数组合

Posted

技术标签:

【中文标题】Haskell 和函数组合【英文标题】:Haskell and function composition 【发布时间】:2016-01-12 23:16:22 【问题描述】:

我在 Haskell 中学习了一些基本的函数组合,当我在玩耍时,我意识到了一些我无法真正解释的东西。当我使用以下代码块时,编译器似乎对此很满意并且工作正常:

doSomeX x = if x==7 then True else False
doSomeY (x,y) = x+y+1
doSomeXY = doSomeX.doSomeY

但是,当我将 doSomeY 拆分为 2 个 args 而不是一对时,即:

doSomeX x = if x==7 then True else False
doSomeY x y = x+y+1
doSomeXY = doSomeX.doSomeY

我收到以下错误:

 No instance for (Num a0) arising from a use of `doSomeY'
 The type variable `a0' is ambiguous
 Relevant bindings include
   doSomeXY :: a0 -> Bool (bound at test.hs:21:1)
 Note: there are several potential instances:
   instance Integral a => Num (GHC.Real.Ratio a)
     -- Defined in `GHC.Real'
   instance Num Integer -- Defined in `GHC.Num'
   instance Num Double -- Defined in `GHC.Float'
   ...plus three others
 In the second argument of `(.)', namely `doSomeY'
 In the expression: doSomeX . doSomeY
 In an equation for `doSomeXY': doSomeXY = doSomeX . doSomeY

我真的不明白为什么。在这两种情况下,doSomeY 的返回类型与函数 doSomeX 的 arg 类型相同,为什么 doSomeY 的输入类型会有所不同?我在这里遗漏了一些基本的东西吗?

谢谢

【问题讨论】:

你明白为什么使用等效的doSomeY x = \y -> x + y + 1了吗? 【参考方案1】:

差异是由doSomeY 在第一种情况下产生一个数字与在第二种情况下应用于一个参数时产生一个函数引起的。

给定

doSomeX x = if x==7 then True else False
doSomeY x y = x+y+1

我们可以推断类型(这些不是最通用的类​​型,但它们可以满足我们的目的):

doSomeX :: Int -> Bool
doSomeY :: Int -> Int -> Int

记住类型签名中的->关联到右边,所以doSomeY的类型等价于

doSomeY :: Int -> (Int -> Int)

考虑到这一点,考虑(.)的类型:

(.) :: (b -> c) -> (a -> b) -> a -> c

如果你定义

doSomeXY = doSomeX.doSomeY

...相当于(.) doSomeX doSomeY,表示(.)的第一个参数是doSomeX,第二个参数是doSomeY。因此,b -> c 类型((.) 的第一个参数)必须匹配Int -> Bool 类型(doSomeX 的类型)。所以

b ~ Int
c ~ Bool

因此,

(.) doSomeX :: (a -> Int) -> a -> Bool

现在,将此应用于doSomeY 会导致类型错误。如上所述,

doSomeY :: Int -> (Int -> Int)

因此,当推断(.) doSomeX doSomeY 的类型时,编译器必须将a -> Int(.) doSomeX 的第一个参数)与Int -> (Int -> Int)doSomeY 的类型)统一起来。 a可以和Int统一,但是后半部分不行。因此编译器会出错。

【讨论】:

【参考方案2】:

(.) 定义为

(.) f g x = f (g x)

所以(f . g) x y = (.) f g x y = f (g x) y,而不是你想要的f (g x y)

另一方面,(f . g) (x,y) = f (g (x,y)),因为(x,y)一个 值,一个 2 元组,所以你的第一个版本是可以的。

【讨论】:

以上是关于Haskell 和函数组合的主要内容,如果未能解决你的问题,请参考以下文章

具有两个参数的 Haskell 组合

Haskell中两个列表元素的所有组合

关于haskell组合的错误

你如何计算 Haskell 列表中的所有列表组合?

Haskell入门篇九:高阶函数(中)

Monads(Haskell)的主要目的[重复]