21

我有以下功能:

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类型基本上只是一个容器:

data Chars = Chars {
               curData  :: [Int],
               curIndex :: Int
               -- etc.
             }

细节并不那么重要,我只想知道这个函数是否有办法返回 aChars而不是 a IO Chars

如果没有,我如何将它作为参数传递给接受 a 的函数Chars?我对 Haskell I/O 有点陌生,但我不认为我希望所有作为参数的函数Chars都必须IO Chars作为参数,然后提取并重新打包它们。似乎没有必要。

谢谢!

4

2 回答 2

27

你不能,因为那会违反引用透明性

Haskell 中的 IO 以这种方式精确区分其结果和效果可能会因与环境/用户的交互而变化的操作和当您使用相同的输入参数调用它们时其结果不会改变的纯函数。

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

myPureFunction :: Chars -> ...

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

如果您不熟悉 Haskell 中的 IO,您可能希望查看学习 Haskell 中的输入和输出章节!真实世界的 Haskell

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

于 2012-07-13T08:50:35.687 回答
11

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

关键是,如果执行任何 I/O,程序的行为和结果可能不仅仅取决于所使用函数的显式参数,因此必须在类型中声明它IO something

您可以通过将结果IO a绑定到main(或从 调用的东西main)中来使用纯函数中的操作结果,然后应用纯函数,将结果绑定到 a 中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
于 2012-07-13T08:54:03.520 回答