Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get normal value from IO action in Haskell

Tags:

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!

like image 567
Benjamin Kovach Avatar asked Jul 13 '12 08:07

Benjamin Kovach


People also ask

What is IO () Haskell?

IO is the way how Haskell differentiates between code that is referentially transparent and code that is not. IO a is the type of an IO action that returns an a . You can think of an IO action as a piece of code with some effect on the real world that waits to get executed.

Is IO a monad Haskell?

The IO type constructor provides a way to represent actions as Haskell values, so that we can manipulate them with pure functions. In the Prologue chapter, we anticipated some of the key features of this solution. Now that we also know that IO is a monad, we can wrap up the discussion we started there.

What is an I/O action?

Input refers to the signals or instructions sent to the computer. Output refers to the signals sent out from the computer. This term is also known as I/O operations, which references the input and output actions.

Is IO in Haskell pure?

I've had the IO monad described to me as a State monad where the state is "the real world". The proponents of this approach to IO argue that this makes IO operations pure, as in referentially transparent.


2 Answers

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.

like image 84
Riccardo T. Avatar answered Sep 20 '22 14:09

Riccardo T.


It's impossible (I lie, there is an extremely unsafe way to cheat your way out of it).

The point is that if any I/O is performed, the behaviour and result of your programme may not depend only on explicit arguments to the used functions, thus that must be declared in the type by having it IO something.

You use the result of an IO a action in a pure function by binding the result in main (or something called from main) and then applying the pure function, binding the result in a let,

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

or, if the function you want to apply to chars has type Chars -> IO b

main = do     chars <- get cs     doSomething chars 
like image 44
Daniel Fischer Avatar answered Sep 18 '22 14:09

Daniel Fischer