为什么 countInFile1 & countInFile3 有编译器错误,而 countInFile0 & countInFile2 没有。这四个都是一样的。
count :: String -> String -> Int
count w = length . filter (==w) . words
present :: String -> String -> IO String
present w = return . show . count w
-- VALID: pointed readFile, regular present
countInFile0 :: String -> FilePath -> IO ()
countInFile0 w f = putStrLn =<< present w =<< readFile f
-- INVALID: pointless readFile, regular present
countInFile1 :: String -> FilePath -> IO ()
countInFile1 w = putStrLn =<< present w =<< readFile
-- VALID: pointed readFile, inline present
countInFile2 :: String -> FilePath -> IO ()
countInFile2 w f = putStrLn =<< (return . show . count w) =<< readFile f
-- INVALID: pointless readFile, inline present
countInFile3 :: String -> FilePath -> IO ()
countInFile3 w = putStrLn =<< (return . show . count w) =<< readFile
main = do
countInFile0 "bulldogs" "bulldogs.txt"
countInFile1 "bulldogs" "bulldogs.txt"
countInFile2 "bulldogs" "bulldogs.txt"
countInFile3 "bulldogs" "bulldogs.txt"
还有为什么 countInFile3 有这个额外的错误,而 countInFile1 没有:
example_one.hs:21:27:
No instance for (Monad ((->) FilePath))
arising from a use of `=<<'
Possible fix:
add an instance declaration for (Monad ((->) FilePath))
In the expression:
putStrLn =<< (return . show . count w) =<< readFile
In an equation for `countInFile3':
countInFile3 w
= putStrLn =<< (return . show . count w) =<< readFile
最佳答案
与两者 countInFile1
和 countInFile3
,因为您正在编写形式为 a -> IO b
的三件事,你在想所谓的 Kleisli 作文,<=<
来自 Control.Monad
.尝试
countInFile1 w = putStrLn <=< present w <=< readFile
countInFile3 w = putStrLn <=< return . show . count w <=< readFile
或者你可以写
countInFile3 w file = ... =<< readFile file
,就像您在其他地方所做的那样。 readFile file
(带参数)是一个 IO String
,所以它可以通过 >>=
传递或 =<<
给任何 String -> IO b
.但这并不像你想要的那么时髦。 readFile
本身就是一个 FilePath -> IO String
所以它可以是 >=>
'd 与任何 String -> IO b
制作 FilePath -> IO b
以此类推 b -> IO c
等,在您的情况下以 FilePath -> IO ()
结尾第二个错误来自 ghc 试图读取
=<< readFile
, 为此需要 readFile
对于某些 monad m 来说是 m b,所以它决定于 Monad ((->) FilePath)
(这实际上对 Control.Monad.Instances
有意义,但只会延迟获得第一个错误。)如果添加
file
这些参数是这样的, countInFile1 w file = (putStrLn <=< present w <=< readFile) file
并且您可能正在解析
countInFile2
和 countInFile0
这样,同时解释 =<<
如 <=<
实际上他们是这样的: countInFile0 w file = putStrLn =<< present w =<< (readFile file)
区别是相同的
f n = (even . (+1) . (*3)) n
或等效地
f = even . (+1) . (3*)
另一方面
f n = even $ (+1) $ 3 * n -- cp. your 0 and 2
如果删除
n
从这里两边 f = even $ (+1) $ (3*) -- cp. your 1 and 3
你会得到一个类似于你看到的类型错误:
No instance for (Integral (a0 -> a0)) arising from a use of `even'
您在哪里使用
$
您需要参数 n
-- 就像你使用的地方 >>=
或 =<<
您需要参数 file
.与 .
,与 <=<
一样,你没有。
关于haskell - 无意义编程时 readFile 和 IO monad 之间没有合作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12470078/