为什么编译好:
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/"'
答案 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
,这是一个从ByteString
到ByteString
的函数{{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
即。 ($)
未替换为(.)
;相反,整个表达被重新排列。