如何在 IO 函数中使用纯函数?:-/
例如:我正在读取一个文件(IO 函数),我想通过使用具有引用透明性的纯函数来解析它的上下文,一个字符串。
似乎这样的世界,纯函数和 IO 函数,是分开的。我怎么可能桥接他们?
如何在 IO 函数中使用纯函数?:-/
例如:我正在读取一个文件(IO 函数),我想通过使用具有引用透明性的纯函数来解析它的上下文,一个字符串。
似乎这样的世界,纯函数和 IO 函数,是分开的。我怎么可能桥接他们?
最简单的方法是使用fmap,它具有以下类型:
fmap :: (Functor f) => (a -> b) -> f a -> f b
IOimplements Functor,这意味着我们可以通过替换IOforf来专门化上述类型:
fmap :: (a -> b) -> IO a -> IO b
换句话说,我们采用一些将as 转换为bs 的函数,并使用它来更改IO动作的结果。例如:
getLine :: IO String
>>> getLine
Test<Enter>
Test
>>> fmap (map toUpper) getLine
Test<Enter>
TEST
那里刚刚发生了什么?好吧,map toUpper有类型:
map toUpper :: String -> String
它接受 aString作为参数,并返回 aString作为结果。具体来说,它将整个字符串大写。
现在,让我们看一下 的类型fmap (map toUpper):
fmap (map toUpper) :: IO String -> IO String
我们已经升级了我们的函数来处理IO值。它将IO操作的结果转换为返回大写字符串。
我们也可以使用do符号来实现这一点,以:
getUpperCase :: IO String
getUpperCase = do
str <- getLine
return (map toUpper str)
>>> getUpperCase
Test<Enter>
TEST
事实证明,每个 monad 都具有以下属性:
fmap f m = do
x <- m
return (f x)
换句话说,如果任何类型实现Monad了 ,那么它也应该总是能够实现Functor,使用上面的定义。事实上,我们总是可以使用 的liftM作为默认实现fmap:
liftM :: (Monad m) => (a -> b) -> m a -> m b
liftM f m = do
x <- m
return (f x)
liftM与 相同fmap,除了专门用于 monad,它不像函子那样通用。
所以如果你想转换一个IO动作的结果,你可以使用:
fmap,liftM, 或者do符号这真的取决于你喜欢哪一个。我个人推荐fmap。
You can also consider liftM function from Control.Monad.
A little example to help you (run it into ghci as you are under the IO Monad)
$ import Control.Monad -- to emerge liftM
$ import Data.Char -- to emerge toUpper
$ :t map to Upper -- A pure function
map toUpper :: [Char] -> [Char]
$ :t liftM
liftM :: Monad m => (a1 -> r) -> m a1 -> m r
$ liftM (map toUpper) getLine
亚历克斯霍斯曼帮助了我。他说:
“也许我误会了,但这听起来很简单?do {x <- ioFunc; return (pureFunc x)}”
然后我解决了我的问题:
import System.IO
import Data.List
getFirstPart line Nothing = line
getFirstPart line (Just index) = fst $ splitAt index line
eliminateComment line =
getFirstPart line $ elemIndex ';' line
eliminateCarriageReturn line =
getFirstPart line $ elemIndex '\r' line
eliminateEntersAndComments :: String -> String
eliminateEntersAndComments text =
concat $ map mapFunction $ lines text
where
mapFunction = (++ " ") . eliminateCarriageReturn . eliminateComment
main = do {
contents <- readFile "../DWR-operators.txt";
return (eliminateEntersAndComments contents)
}
实际答案如下:
main = do
val <- return (purefunc ...arguments...)
...more..actions...
return将其包装在适当的 monad 中,以便do可以将其分配给val.