这里的两位非常简单的功能f
和g
.
{-# LANGUAGE ScopedTypeVariables #-} module Test where import Control.Applicative f :: IO () f = do y <- (<*>) (pure (show . (*10))) (read <$> readFile "data") writeFile "out" y g :: IO () g = do y <- (readFile "data" >>= return . show . (*10) . read) writeFile "out" y
读取文件并*10
在f
写入应用性风格pure
和(<*>)
.读取和*10
输入的文件g
是以monadic样式编写的>>=
.(我一直在使用刻意避免liftM
在g
强调以下问题).
f
和之间的语义差异是g
什么?或者在这种情况下,它只是一种风格选择吗?
show . (*10) . read
是一个"非monadic"函数 - 我的意思是,它在IO monad中没有做任何事情,正如你可以从它的类型中看到的那样.
>>= return .
可以缩短为
`liftM`
但
`liftM`
应始终相当于
`fmap`
fmap
既不需要monad类型类也不需要应用类型类,它只需要仿函数类型类.
现在把注意力转向应用版本,这个:
(<*>) (pure ...
相当于<$>
,这只是fmap
.
因此,在这两种情况下,我们"真的"只是在函数中使用函数操作,在阅读和写作之间,虽然你以稍微不同的方式组合了函数(我们需要应用一个或多个"法则"来翻译这两个函数)相互之间的版本),语义是 - 或应该 - 相同.无论如何,当然他们和IO monad在一起.