Haskell和函数组成

Rak*_*kim 2 haskell function-composition

我在Haskell学习了一些基本的功能组合,当我在玩的时候,我意识到我无法解释的东西.当我使用下面的代码块时,编译器似乎对此感到高兴并且工作正常:

doSomeX x = if x==7 then True else False
doSomeY (x,y) = x+y+1
doSomeXY = doSomeX.doSomeY
Run Code Online (Sandbox Code Playgroud)

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

doSomeX x = if x==7 then True else False
doSomeY x y = x+y+1
doSomeXY = doSomeX.doSomeY
Run Code Online (Sandbox Code Playgroud)

我收到以下错误:

 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
Run Code Online (Sandbox Code Playgroud)

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

谢谢

Fre*_*abe 6

这种差异是由于doSomeY在第一种情况下产生一个数字而在第二种情况下产生一个函数时应用于一个参数.

特定

doSomeX x = if x==7 then True else False
doSomeY x y = x+y+1
Run Code Online (Sandbox Code Playgroud)

我们可以推断出类型(这些类型不是最常用的类型,但它们可以用于我们的目的):

doSomeX :: Int -> Bool
doSomeY :: Int -> Int -> Int
Run Code Online (Sandbox Code Playgroud)

请记住,->在右侧的类型签名关联中,所以类型doSomeY相当于

doSomeY :: Int -> (Int -> Int)
Run Code Online (Sandbox Code Playgroud)

考虑到这一点,请考虑以下类型(.):

(.) :: (b -> c) -> (a -> b) -> a -> c
Run Code Online (Sandbox Code Playgroud)

如果你定义

doSomeXY = doSomeX.doSomeY
Run Code Online (Sandbox Code Playgroud)

...相当于(.) doSomeX doSomeY,它意味着第一个参数(.)doSomeX和第二个参数是doSomeY.因此,类型b -> c(第一个参数(.))必须与类型Int -> Bool(类型doSomeX)匹配.所以

b ~ Int
c ~ Bool
Run Code Online (Sandbox Code Playgroud)

因此,

(.) doSomeX :: (a -> Int) -> a -> Bool
Run Code Online (Sandbox Code Playgroud)

现在,应用它会doSomeY导致类型错误.正如刚才提到的,

doSomeY :: Int -> (Int -> Int)
Run Code Online (Sandbox Code Playgroud)

因此,当推断(.) doSomeX doSomeY编译器的类型必须统一a -> Int(第一个参数(.) doSomeX)与Int -> (Int -> Int)(类型doSomeY).a可以统一Int,但下半年不会工作.因此编译器barfs.