函数组合和$ - 一个编译,另一个没有

时间:2014-07-15 11:34:10

标签: haskell

为什么编译好:

import Network.HTTP.Conduit (simpleHttp)
import qualified Data.ByteString.Lazy.Char8 as L

main = L.putStrLn . L.take 500 =<< simpleHttp "http://stackoverflow.com/"

但这不是:

main = L.putStrLn $ L.take 500 =<< simpleHttp "http://stackoverflow.com/"

对我而言,这些完全一样。第二种情况中的错误是:

Couldn't match type `L.ByteString' with `m0 b0'
Expected type: L.ByteString -> m0 b0
  Actual type: L.ByteString -> L.ByteString
In the return type of a call of `L.take'
In the first argument of `(=<<)', namely `L.take 500'
In the second argument of `($)', namely
  `L.take 500 =<< simpleHttp "http://stackoverflow.com/"'

Couldn't match expected type `L.ByteString'
            with actual type `m0 b0'
In the second argument of `($)', namely
  `L.take 500 =<< simpleHttp "http://stackoverflow.com/"'

2 个答案:

答案 0 :(得分:17)

(.)绑定强于(=<<)($)绑定弱于(=<<)。因此,第一个表达式可以写成

main = (L.putStrLn . L.take 500) =<< simpleHttp "http://stackoverflow.com/"

和第二个

main = L.putStrLn $ (L.take 500 =<< simpleHttp "http://stackoverflow.com/")

因此在后一个表达式中,函数=<<a -> m b作为其第一个参数)被赋予L.take 500,这是一个从ByteStringByteString的函数{{1}}。这不适合在一起,这就是错误信息所说的内容。

答案 1 :(得分:3)

(.)($) 从不可互换,因为他们的类型不同:

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

它必须保持b ~ (a->b)c ~ (a->c),而两者都被视为&#34;无限类型&#34;,导致&#34;发生检查&#34;错误,例如在

Prelude> let g a b = let x = a . b ; y = a $ b in undefined

<interactive>:1:24:
    Occurs check: cannot construct the infinite type: a = a1 -> a
    ....

在你的例子中更是如此,当一个用另一个替换时会导致表达式完全不同的解析,因为它们的优先级完全不同:

  

前奏&GT; :我(。)
  (。)::(b - &gt; c) - &gt; (a - &gt; b) - &gt; a - &gt; c - 在GHC.Base中定义    infixr 9。
  前奏&GT; :我($)
  ($)::(a - &gt; b) - &gt; a - &gt; b - 在GHC.Base中定义    infixr 0 $

编辑:有时,in very specific circumstances.$ 可以互换。具体而言,f $ g $ ... $ h $ x可以写为f . g . ... . h $ x

这与我的开场陈述并不矛盾,因为

 f $ g $ x = f $ (g $ x) = ($) f (($) g x) 

,而

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

即。 ($) 替换为(.);相反,整个表达被重新排列。