Cómo obtener el valor normal de la acción IO en Haskell

Tengo la siguiente función:

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 

y quiero obtener un Chars de él, no una acción IO. No tengo idea de cómo hacer esto, o si es posible.

Chars es básicamente un contenedor con un [Int] llamado curData y un Int llamado curIndex. Los detalles no son tan importantes, solo quiero saber si hay una forma de que esta función devuelva un Chars lugar de un IO Chars .

Si no, ¿cómo paso esto como argumento a una función que toma un Chars ? Soy algo nuevo para Haskell IO, pero no creo que quiera que todas mis funciones que toman Chars como argumentos tengan que tomar IO Chars como argumentos y luego extraerlos y volver a empaquetarlos. Parece innecesario

¡Gracias!

No se puede, porque eso violaría la transparencia referencial .

IO en Haskell se hace de esta manera exactamente para distinguir entre acciones cuyo resultado y efectos pueden variar dependiendo de la interacción con el entorno / usuario y funciones puras cuyos resultados no van a cambiar cuando los llames con los mismos parámetros de entrada.

Para pasar el resultado a una función pura tomando un Chars en la entrada, debe llamar su acción IO a otra acción IO, vincular el resultado con el operador <- a una variable y pasarlo a su función pura. Ejemplo de pseudocódigo:

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

Si eres nuevo en IO en Haskell, puedes echarle un vistazo a los capítulos de Entrada y Salida en Learn You a Haskell for a Great Good! y Real World Haskell .

En realidad, hay una forma de obtener un valor puro de una acción IO, pero en su caso no debería hacerlo, ya que está interactuando con el entorno: la forma insegura está bien solo cuando puede garantizar que está no violar la transparencia referencial.

Es imposible (Miento, hay una manera extremadamente insegura de engañar para salir de eso).

El punto es que si se realiza alguna E / S, el comportamiento y el resultado de su progtwig pueden no depender solo de los argumentos explícitos de las funciones utilizadas, por lo que debe declararse en el tipo al tener IO something .

Usas el resultado de IO a acción IO a en una función pura vinculando el resultado en main (o algo llamado desde main ) y luego aplicando la función pure, vinculando el resultado en let ,

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

o, si la función que desea aplicar a chars tiene el tipo Chars -> IO b

 main = do chars <- get cs doSomething chars