Haskell - 如何在IO函数中使用纯函数?

Jua*_*nto 5 io haskell referential-transparency

如何在IO函数中使用纯函数?: - /

例如:我正在读取一个文件(IO函数),我想通过使用具有引用透明性的纯函数来解析其上下文,一个字符串.

似乎这样的世界,纯函数和IO函数是分开的.我怎么可能桥接他们?

Gab*_*lez 10

最简单的方法是使用fmap,具有以下类型:

fmap :: (Functor f) => (a -> b) -> f a -> f b
Run Code Online (Sandbox Code Playgroud)

IO实现了Functor,这意味着我们可以通过替换专门上述类型IOf获得:

fmap :: (a -> b) -> IO a -> IO b
Run Code Online (Sandbox Code Playgroud)

换句话说,我们采用一些将as 转换为bs的函数,并使用它来改变IO动作的结果.例如:

getLine :: IO String

>>> getLine
Test<Enter>
Test
>>> fmap (map toUpper) getLine
Test<Enter>
TEST
Run Code Online (Sandbox Code Playgroud)

刚刚发生了什么?好吧,map toUpper有类型:

map toUpper :: String -> String
Run Code Online (Sandbox Code Playgroud)

它需要一个String参数,并返回String一个结果.具体来说,它会对整个字符串进行大写.

现在,让我们来看看类型fmap (map toUpper):

fmap (map toUpper) :: IO String -> IO String
Run Code Online (Sandbox Code Playgroud)

我们已经升级了我们的功能以处理IO价值观.它将IO动作的结果转换为返回上部字符串.

我们也可以使用do符号来实现:

getUpperCase :: IO String
getUpperCase = do
    str <- getLine
    return (map toUpper str)

>>> getUpperCase
Test<Enter>
TEST
Run Code Online (Sandbox Code Playgroud)

事实证明,每个monad都有以下属性:

fmap f m = do
    x <- m
    return (f x)
Run Code Online (Sandbox Code Playgroud)

换句话说,如果任何类型实现Monad,那么它应该总是能够Functor使用上面的定义来实现.实际上,我们总是可以使用liftM默认的实现fmap:

liftM :: (Monad m) => (a -> b) -> m a -> m b
liftM f m = do
    x <- m
    return (f x)
Run Code Online (Sandbox Code Playgroud)

liftM是相同的fmap,除了专用于单子,这是不一般的函子.

因此,如果要转换操作的结果IO,可以使用:

  • fmap,
  • liftM, 要么
  • do 符号

这取决于你喜欢哪一个.我个人推荐fmap.


Jua*_*nto 1

亚历克斯霍斯曼帮助了我。他说:

“也许我误解了,但这听起来很简单?做 {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)
}
Run Code Online (Sandbox Code Playgroud)