【问题标题】:Haskell - How can I use pure functions inside IO functions?Haskell - 如何在 IO 函数中使用纯函数?
【发布时间】:2013-02-01 17:28:05
【问题描述】:

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

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

似乎纯函数和 IO 函数这样的世界是分开的。我怎样才能跨越它们?

【问题讨论】:

  • 您阅读了哪些教程 - haskell 中对 IO 的每个介绍都涵盖了您的问题。解决方案是创建 IO Monad。
  • 谢谢。我解决了这个问题。看下面:

标签: haskell io referential-transparency


【解决方案1】:

最简单的方法是使用fmap,其类型如下:

fmap :: (Functor f) => (a -> b) -> f a -> f b

IO 实现了Functor,这意味着我们可以通过将IO 替换为f 来特化上述类型得到:

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

它将String 作为参数,并返回String 作为结果。具体来说,它将整个字符串大写。

现在,我们来看看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)

liftMfmap 相同,除了专门用于 monad,它不像函子那样通用。

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

  • fmap,
  • liftM,或
  • do 表示法

这真的取决于你喜欢哪一个。我个人推荐fmap

【讨论】:

  • 这不是解释如何提取 IO 操作的结果,而不是如何从 IO 操作调用纯函数吗?
【解决方案2】:

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

“也许我理解错了,但这听起来很简单? 做 {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)
}

【讨论】:

    【解决方案3】:

    您还可以考虑 Control.Monad 中的 liftM 函数。
    一个帮助你的小例子(在 IO Monad 下运行到 ghci)

    $ 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 
    

    【讨论】:

      【解决方案4】:

      实际答案如下:

      main = do
        val <- return (purefunc ...arguments...)
        ...more..actions...

      return 将其包装在适当的 monad 中,以便 do 可以将其分配给 val

      【讨论】:

        猜你喜欢
        • 2016-03-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-06-16
        • 1970-01-01
        • 1970-01-01
        • 2021-10-01
        相关资源
        最近更新 更多