readFile& amp; IO monad编程时无意义

时间:2012-09-18 03:41:27

标签: haskell io monads pointfree

为什么countInFile1& countInFile3& countInFile3有编译错误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

2 个答案:

答案 0 :(得分:9)

同时使用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 filereadFile file(带参数)是IO String,因此可以>>==<<传递给任何String -> IO b。但这并不像你想要的那样猛烈。 readFile只是FilePath -> IO String >=>所以String -> IO b可以FilePath -> IO b与任何b -> IO c建立FilePath -> IO (),依此类推=<< readFile在您的情况下以readFile

结尾的等等

第二个错误来自ghc尝试阅读Monad ((->) FilePath),为此需要Control.Monad.Instances为某些monad m为mb,因此它会在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.一样,您需要参数<=<。对于{{1}},与{{1}}一样,您没有。{/ p>

答案 1 :(得分:8)

函数应用程序的优先级高于infix =<<运算符。

所以f =<< g a相当于f =<< (g a)而不是(f =<< g) a