Подтвердить что ты не робот

Как получить нормальное значение от операций ввода-вывода в Haskell

У меня есть следующая функция:

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 - это просто контейнер с [Int], называемый curData, и Int, называемый curIndex. Специфика не так важна, я просто хочу знать, есть ли способ вернуть эту функцию Chars вместо IO Chars.

Если нет, как передать это как аргумент функции, которая принимает Chars? Я новичок в Haskell IO, но я не думаю, что хочу, чтобы все мои функции принимали Chars в качестве аргументов вместо этого, чтобы принимать IO Chars в качестве аргументов, а затем извлекать и переупаковывать их. Это кажется ненужным.

Спасибо!

4b9b3361

Ответ 1

Вы не можете, потому что это нарушит ссылочную прозрачность.

IO в Haskell делается именно так, чтобы различать действия, результат и эффекты которых могут варьироваться в зависимости от взаимодействия с окружающей средой/пользователем и чистыми функциями, результаты которых не будут меняться, когда вы вызываете их с одинаковыми входными параметрами.

Чтобы передать результат чистой функции, принимающей вход Chars, вам нужно вызвать свое действие ввода-вывода в другое действие ввода-вывода, привязать результат с оператором <- к переменной и передать ее в вашу чистую функция. Пример псевдокода:

myPureFunction :: Chars -> ...

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

Если вы новичок в IO в haskell, вы можете взглянуть на главы ввода и вывода в Учить вас Haskell для отличного хорошего! и Real World Haskell.

На самом деле есть способ просто получить чистое значение из действия IO, но в вашем случае вы не должны этого делать, поскольку вы взаимодействуете с окружающей средой: небезопасный способ подходит только тогда, когда вы можете гарантировать вы не нарушаете ссылочную прозрачность.

Ответ 2

Это невозможно (я лгу, есть чрезвычайно опасный способ обмануть свой выход).

Дело в том, что если выполняется какой-либо ввод-вывод, поведение и результат вашей программы могут не зависеть только от явных аргументов от используемых функций, поэтому они должны быть объявлены в типе, имея его IO something.

Вы используете результат действия IO a в чистой функции, привязывая результат в main (или что-то называемое от main), а затем применяя чистую функцию, привязывая результат к 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