Haskell和函数组成

时间:2016-01-12 23:16:22

标签: haskell function-composition

我正在学习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的输入类型会有所不同?我在这里遗漏了一些基本的东西吗?

由于

2 个答案:

答案 0 :(得分:6)

差异是由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 -> BooldoSomeX的类型)匹配。所以

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统一,但下半场无法正常工作。因此编译器barfs。

答案 1 :(得分:3)

(.)定义为

(.) 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元组,所以你的第一个版本没问题。