Como obter o valor normal da ação IO em Haskell

Eu tenho a seguinte 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 

e eu estou querendo obter um Chars , não uma ação de IO. Eu não tenho ideia de como fazer isso, ou se é mesmo possível.

Chars é basicamente apenas um container com um [Int] chamado curData e um Int chamado curIndex. Os detalhes não são tão importantes, só quero saber se há uma maneira de essa function retornar um Chars vez de um IO Chars .

Se não, como eu passo isso como um argumento para uma function que leva um Chars ? Eu sou meio novo no Haskell IO, mas eu não acho que eu quero todas as minhas funções que levam Chars como argumentos para ter que IO Chars como argumentos, e então extrair e reempacotá-los. Parece desnecessário.

Obrigado!

Você não pode, porque isso violaria a transparência referencial .

O IO em Haskell é feito exatamente para distinguir entre ações cujo resultado e efeitos podem variar dependendo da interação com o ambiente / usuário e funções puras cujos resultados não vão mudar quando você os chamar com os mesmos parâmetros de input.

Para passar o resultado para uma function pura usando uma input Chars in você precisa chamar sua ação de IO para outra ação de IO, ligar o resultado com o operador <- a uma variável e passá-la para sua function pura. Exemplo de pseudocódigo:

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

Se você é novo em IO no haskell, você pode querer dar uma olhada nos capítulos Input e Output em Learn You a Haskell para um ótimo bem! e Mundo Real Haskell .

Na verdade, existe uma maneira de obter simplesmente um valor puro de uma ação de IO, mas, no seu caso, você não deve fazer isso, pois está interagindo com o ambiente: a maneira insegura está correta apenas quando você pode garantir que está não violar a transparência referencial.

É impossível (eu minto, há uma maneira extremamente insegura de enganar você).

O ponto é que, se qualquer E / S é executada, o comportamento e o resultado de seu programa podem não depender apenas de argumentos explícitos para as funções usadas, portanto, isso deve ser declarado no tipo por tê-lo como IO something .

Você usa o resultado de um IO a ação em uma function pura ligando o resultado em main (ou algo chamado de main ) e então aplicando a function pura, ligando o resultado em um let ,

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

ou, se a function que você deseja aplicar a chars tiver tipo Chars -> IO b

 main = do chars <- get cs doSomething chars