2013-02-17 37 views
5

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

例如:我正在读文件(IO函数),我想通过使用具有参照透明度的纯函数来解析其上下文(字符串)。

似乎这样的世界,纯粹的功能和IO功能是分开的。我怎样才能弥合他们?

+3

你读过什么教程 - 每一个在哈斯克尔IO介绍涵盖你的问题。解决方案是创建IO Monad。 – epsilonhalbe 2013-02-17 00:26:42

+0

谢谢。我解决了这个问题。 Look bellow: – 2013-02-17 00:50:02

回答

1

Alex Horsman帮助了我。他说:

“也许我的误解,但是这听起来很简单 做{X < - ioFunc;回报(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) 
} 
2

您也可以从Control.Monad中考虑liftM函数。
一个小例子来帮助你(运行到ghci中,你是下IO单子)

$ 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 
8

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

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

IO执行Functor,这意味着我们可以通过用IO替代f来专门化上述类型,以获得:

fmap :: (a -> b) -> IO a -> IO b 

换句话说,我们采用一些函数将a s转换为b s,并使用它来更改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 

事实证明,每一个单子具有以下特性:

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,除了专门给单子,这不是一般的函子。

所以,如果你想改变一个IO作用的结果,你可以使用:

  • fmap
  • liftM,或
  • do符号

这是真的了给你你喜欢哪一个。我个人建议fmap

+0

这不会解释如何提取IO操作的结果,而不是如何从IO操作调用纯函数* – 2015-06-11 19:56:26

0

实际答案如下:

main = do 
    val <- return (purefunc) 

return包装它在适当的单子这样做可以把它分配给VAL。