Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.1k views
in Technique[技术] by (71.8m points)

io monad - How to get normal value from IO action in Haskell

I have the following function:

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

and I'd like to get a Chars value out of it, not an IO action. I have no idea how to do this, or if it is even possible.

The Chars type is basically just a container:

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

The specifics aren't that important, I just want to know if there's a way for this function to return a Chars instead of an IO Chars.

If not, how do I pass this as an argument to a function that takes a Chars? I'm kind of new to Haskell I/O, but I don't think I want all of my functions that take Chars as arguments to instead have to take IO Chars as arguments, and then extract and repackage them. It seems unnecessary.

Thanks!

Question&Answers:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You can't, because that would violate referential transparency.

IO in Haskell is made this way exactly to distinguish between actions whose result and effects may vary depending on the interaction with the environment/user and pure functions whose results are not going to change when you call them with the same input parameters.

In order to pass the result to a pure function taking a Chars in input you have to call your IO action into another IO action, bind the result with the <- operator to a variable and pass it to your pure function. Pseudocode example:

myPureFunction :: Chars -> ...

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

If you're new to IO in haskell, you may wish to have a look at the Input and Output chapters in Learn You a Haskell for a Great Good! and Real World Haskell.

There is actually a way to simply get a pure value out of an IO action, but in your case you shouldn't do it, as you're interacting with the environment: the unsafe way is ok only when you can guarantee you're not violating referential transparency.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

1.4m articles

1.4m replys

5 comments

56.8k users

...