Как обернуть символьный литерал в монаду ввода / вывода в Haskell? - PullRequest
0 голосов
/ 10 марта 2019

Я знаю, что вы должны свернуть операции, которые вы хотите выполнить с результатом в монаде, а не распаковывать вещи из монады.

То, что я не могу найти, это какие-то идиотские примеры того, как это сделать.

Например, я хочу сделать что-то вроде этого:

myFunction = do
    c <- getChar
    if (c == 'q')
        then putStrLn "take action 1"
        else putStrLn "take action 2"

Но вы не можете напрямую сравнивать литерал char с IO Char.

Версия GHCi: 8.4.4.

Сообщение об ошибке:

[1 из 2] Компиляция Lib (/Users/jamesstrieter/hask-tink/src/Lib.hs, интерпретируется)

/ Users / jamesstrieter / hask-tink / src / Lib.hs: 66: 18: ошибка: • Не удалось сопоставить ожидаемый тип 'IO char' с фактическим типом 'Char' • Ввторой аргумент '(==)', а именно '' q '' в выражении: x == 'q' в уравнении для what2do: what2do x = x == 'q' • Соответствующие привязки включают в себя x ::IO char (привязан к /Users/jamesstrieter/hask-tink/src/Lib.hs:66:9) what2do :: IO char -> Bool (привязан к /Users/jamesstrieter/hask-tink/src/Lib.hs:66: 1) |66 |what2do x = x == 'q' |^^^ Не удалось, модули не загружены.

Ответы [ 3 ]

7 голосов
/ 10 марта 2019

Код, который вы разместили, выглядит совершенно правильно и функционально.

do-нотация - это способ работы со значением в монаде.

c <- getChar в блоке do связывает c с символом внутри IO Char, который вы получаете с getChar.Вы можете сравнить c == 'q' просто отлично, потому что c - это обычный символ, а не IO Char.

Чтобы ответить на ваш прямой вопрос, вы можете использовать функцию return для помещения чистого значения в любую монаду, включая IO, поэтому return 'q' «оборачивает» символьный литерал 'q' в монаду.Это не то, что вы хотите в этом случае, код, который у вас уже есть, это то, что вы ищете.

4 голосов
/ 10 марта 2019

Но вы не можете напрямую сравнивать символьный литерал с IO Char.

Конечно, но когда вы «связываете» результат действия ввода-вывода, он больше не IO Char, а просто Char, поэтому он работает.

Другими словами:

Prelude> :t getChar
getChar :: IO Char
Prelude> c <- getChar
x
Prelude> :t c
c :: Char
1 голос
/ 10 марта 2019

Одна из самых важных вещей, которые нужно понять о монаде IO, заключается в том, что выражение m >>= f не не выполняет действие m, и при этом не каждый вызывает функцию f.

Вместо этого он просто создает новое IO действие, которое включает в себя m и f и, когда оно выполнено, наконец выполняет m, извлекает возвращаемое значение извонит f с результатом.

Вот и все.Вся ваша программа на Haskell - это не что иное, как DSL для создания одного действия ввода-вывода, которому назначается main, который для вас выполнит Haskell runtime .

Поэтому, когда вы пишете

-- Rewritten slightly for brevity
myFunction = do
    c <- getChar
    putStrLn (if (c == 'q')
        then "take action 1"
        else "take action 2")

это desugared до

myFunction = getChar >>= (\c -> putStrLn (if (c == 'q') then "take action 1" else "take action 2")

, и вы на самом деле говорите: "Создайте IO действие, содержащее getChar и функцию типа Char -> IO (), такую, что когдаэто действие выполняется, оно выполняет getChar и передает результирующее Char в функцию для создания другого IO действия, которое должно быть выполнено немедленно. "

...