我在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在第一种情况下产生一个数字与在第二种情况下产生一个函数而应用于一个参数时引起的。

给定

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。

关于haskell - Haskell和功能组成,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/34755600/

10-10 14:13