Как получить нормальное значение от операций ввода-вывода в 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
в качестве аргументов, а затем извлекать и переупаковывать их. Это кажется ненужным.
Спасибо!
Ответы
Ответ 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