haskell - 无意义编程时 readFile 和 IO monad 之间没有合作

标签 haskell io monads pointfree

为什么 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

最佳答案

与两者 countInFile1countInFile3 ,因为您正在编写形式为 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 

并且您可能正在解析 countInFile2countInFile0这样,同时解释 =<<<=<实际上他们是这样的:
 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/

相关文章:

haskell - idris 有 MaybeT 吗?

c - 用普通 C 将文本文件读入数组

c++ - 如何在不失去灵活性的情况下摆脱冗长的初始化

haskell - free monads 与 mtl 的争论是什么?

ios - IOS 5下的Haskell内存管理

haskell - 在 Haskell 中观察惰性

dll - 如何构建一个不需要 DLL 的程序

c++ - 将( double )表写入二进制文件 IO C++

haskell - 错误处理和单子(monad)?

haskell - 这个简单的 Haskell 函数是否已经有了一个众所周知的名字?