如何在Haskell中从IO操作中获取正常值

时间:2012-07-13 08:46:02

标签: haskell io monads

我有以下功能:

get :: Chars -> IO Chars
get cs = do
    char <- getChar
    let (dats, idx) = (curData cs, curIndex cs)
    let (x,y:xs) = splitAt idx dats
    let replacement = x ++ (ord char) : xs
    return $ Chars replacement idx

我希望从中获取Chars值, IO操作。我没有想法如何做到这一点,或者甚至可能。

Chars基本上只是一个名为curData的[Int]和名为curIndex的Int的容器。具体细节并不重要,我只是想知道这个函数是否有办法返回Chars而不是IO Chars

如果没有,我如何将其作为参数传递给采用Chars的函数?我是Haskell IO的新手,但我认为我不希望所有以Chars为参数的函数都必须将IO Chars作为参数,然后提取并重新打包它们。这似乎没必要。

谢谢!

2 个答案:

答案 0 :(得分:21)

你不能,因为这会违反referential transparency

Haskell中的IO就是这样做的,以区分根据与环境/用户的交互而结果和效果可能不同的动作以及当使用相同的输入参数调用结果时结果不会改变的纯函数。

为了将结果传递给输入Chars的纯函数,必须将IO操作调用到另一个IO操作中,将结果与<-运算符绑定到变量并传递这是你的纯粹功能。伪代码示例:

myPureFunction :: Chars -> ...

otherAction :: Chars -> IO ()
otherAction cs = do
  myChars <- get cs
  let pureResult = myPureFunction myChars
  ...

如果您是haskell中IO的新手,您可能希望查看Learn You a Haskell for a Great Good!Real World Haskell中的输入和输出章节。

实际上有一种方法可以简单地从IO操作中获取纯值,但在您的情况下,您不应该这样做,因为您正在与环境交互:只有当您能保证时,不安全的方式才可以你没有违反参考透明度。

答案 1 :(得分:9)

这是不可能的(我撒谎,有一种非常不安全的方法可以欺骗你。)

关键是如果执行了任何I / O,程序的行为和结果可能不仅仅依赖于使用函数的显式参数,因此必须通过使用IO something来声明类型

通过将结果绑定在IO a(或从main调用的内容)然后应用纯函数,绑定结果,在纯函数中使用main操作的结果在let

cs ::Chars
cs = undefined

main = do
  chars <- get cs
  let result = pureFunction chars
  print result

或者,如果您要应用于chars的功能类型为Chars -> IO b

main = do
    chars <- get cs
    doSomething chars