Haskell IO单子中的函数组合
Haskell中的Haskell IO单子中的函数组合,haskell,io,monads,function-composition,io-monad,Haskell,Io,Monads,Function Composition,Io Monad,Haskell中的lines函数将字符串的行分隔为一个字符串列表: lines :: String -> [String] readFile函数将文件读入字符串: readFile :: FilePath -> IO String 尝试组合这些函数以获取文件中的行列表会导致类型错误: Prelude> (lines . readFile) "quux.txt" <interactive>:26:10: error: • Couldn't match ty
lines
函数将字符串的行分隔为一个字符串列表:
lines :: String -> [String]
readFile
函数将文件读入字符串:
readFile :: FilePath -> IO String
尝试组合这些函数以获取文件中的行列表会导致类型错误:
Prelude> (lines . readFile) "quux.txt"
<interactive>:26:10: error:
• Couldn't match type ‘IO String’ with ‘[Char]’
Expected type: FilePath -> String
Actual type: FilePath -> IO String
• In the second argument of ‘(.)’, namely ‘readFile’
In the expression: lines . readFile
In the expression: (lines . readFile) "quux.txt"
Prelude>(lines.readFile)“qux.txt”
:26:10:错误:
•无法将类型“IO字符串”与“[Char]”匹配
所需类型:文件路径->字符串
实际类型:文件路径->IO字符串
•在“(.”的第二个参数中,即“readFile”
在表达式中:行。读取文件
在表达式中:(lines.readFile)“qux.txt”
我怎么才能在这里玩单子的把戏呢?你不能单独编写它们,至少不能单独使用
()
。您可以使用fmap
(或其操作员版本
),但:
现在,您可以使用Kleisli合成运算符=>
组合读取文件
(本身是Kleisli箭头)和行
:
-- return . lines itself has type Monad m => String -> m [String]
-- but for our use case we can restrict the type to the monad
-- we are actually interested in.
kleisliLines :: String -> IO [String]
kleisliLines = return . lines
import Control.Monad -- where (>=>) is defined
-- (>=>) :: Monad m => (a -> m b) -> (b -> m c) -> a -> m c
-- Here, m ~ IO
-- a -> FilePath
-- b -> String
-- c -> [String]
(readFile >=> kleisliLines) "quux.txt"
-- m >>= return . f === fmap f m === f <$> m
readFile "quux.txt" >>= kleisliLines
将其与>=
运算符进行比较,后者要求您在将结果馈送到返回之前向readFile
提供文件名。行
:
-- return . lines itself has type Monad m => String -> m [String]
-- but for our use case we can restrict the type to the monad
-- we are actually interested in.
kleisliLines :: String -> IO [String]
kleisliLines = return . lines
import Control.Monad -- where (>=>) is defined
-- (>=>) :: Monad m => (a -> m b) -> (b -> m c) -> a -> m c
-- Here, m ~ IO
-- a -> FilePath
-- b -> String
-- c -> [String]
(readFile >=> kleisliLines) "quux.txt"
-- m >>= return . f === fmap f m === f <$> m
readFile "quux.txt" >>= kleisliLines
到目前为止给出的其他答案是使
行
产生一个空的一元上下文,然后使用一元合成(合成很好,但是使用do
块没有什么丢脸的,比如do内容我使用do符号,然后在我想清理代码时进行合成,如果它能提高清晰度的话。
lines <$> readFile "quux.txt"