如何解决在打印上应用函子
我一直在尝试分别打印 2 个值,我尝试了以下代码:
import System.Directory
main = getCurrentDirectory >>= \x -> (print <$> doesFileExist x) >> (print <$> doesDirectoryExist x)
但它不打印任何内容,但以下代码工作正常:
import System.Directory
main = getCurrentDirectory >>= \x -> doesFileExist x >>= print >> doesDirectoryExist x >>= print
为什么第一个代码不打印任何内容的任何原因?
解决方法
如果对 IO 操作进行 fmap print
,则不会得到执行此打印的 IO
操作。您只会得到一个 IO 操作,它执行原始操作所具有的任何副作用,但它不会产生可打印的值作为结果,而是产生另一个 IO
操作作为结果,然后您可以在单独的步骤中执行该操作:
import Control.Applicative
import Data.Time
printCurrentTime :: IO ()
printCurrentTime = do
tPrinter <- print <$> getCurrentTime
tPrinter
或者,没有 do
符号,
printCurrentTime = print <$> getCurrentTime >>= \tPrinter -> tPrinter
换句话说,
printCurrentTime = print <$> getCurrentTime >>= id
根据单子定律,f <$> a >>= b
与 a >>= b . f
相同,即
printCurrentTime = getCurrentTime >>= id . print
这和简单的一样
printCurrentTime = getCurrentTime >>= print
那可以用 do
符号写成
printCurrentTime = do
t <- getCurrentTime
print t
,
正如评论所述,您会得到一个 IO (IO ())
。我们可以使用 join
去除重复的 monad。
join (print <$> doesFileExist x)
但是“fmap
然后join
”实际上是>>=
的定义(join
和>>=
可以相互定义) .这就是您的 >>=
有效的原因。
在您使用函子映射的第一项中,您因此创建了
print <$> doesFileExist x :: IO (IO ())
确实,doesFileExist :: FilePath -> IO Bool
会返回一个 IO Bool
。现在您要做的是执行函子映射,因此您将 Bool
结果映射到 IO ()
,因此我们现在有一个 IO (IO ())
。此 IO
函数不会打印任何内容,因为 IO ()
是 IO 计算的“结果”,而不是操作。
因此您应该使用:
doesFileExist x >>= print
因为这将对 doesFileExist
的结果起作用,并计算为 IO ()
,它将打印 Bool
ean。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。