Haskell: ввод / вывод и возврат из функции


Пожалуйста, потерпите меня, поскольку я очень новичок в функциональном программировании и Хаскелле. Я пытаюсь написать функцию в Haskell, которая берет список целых чисел, печатает начало указанного списка, а затем возвращает конец списка. Функция должна иметь тип [Integer] - > [Integer]. Чтобы дать немного контекста, я пишу интерпретатор, и эта функция вызывается, когда ее соответствующая команда ищется в ассоциативном списке (ключ-команда, значение-функция).

Здесь это код, который я написал:

dot (x:xs) = do print x
      return xs

Компилятор выдает следующее сообщение об ошибке:

forth.hs:12:1:
Couldn't match expected type `[a]' against inferred type `IO [a]'
  Expected type: ([Char], [a] -> [a])
  Inferred type: ([Char], [a] -> IO [a])
In the expression: (".", dot)

Я подозреваю, что вызов функции print в функции dot-это то, что вызывает выводимый тип IO [a]. Есть ли способ, которым я могу игнорировать возвращаемый тип печати, так как все, что мне нужно вернуть, - это хвост списка, передаваемый в точку.

Заранее благодарю.

3 6

3 ответа:

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

  1. [Int] -> [Int] без выполнения каких-либо операций ввода-вывода или
  2. [Int] -> IO [Int] с IO

Тип dot, выводимый компилятором, является dot :: (Show t) => [t] -> IO [t], но вы можете объявить его [Int] -> IO [Int]:

dot :: [Int] -> IO [Int]

См. IO monad: http://book.realworldhaskell.org/read/io.html


Я не упоминал System.IO.Unsafe.unsafePerformIO, что следует использовать с большой осторожностью и с твердым пониманием его последствий.

Нет, либо ваша функция вызывает побочные эффекты (aka IO, в данном случае печать на экране), либо нет. print делает IO и, следовательно, возвращает что-то в IO, и это не может быть отменено.

И было бы плохо, если бы компилятор мог быть обманут, чтобы забыть о IO. Например, если ваша функция [Integer] -> [Integer] вызывается несколько раз в вашей программе с теми же параметрами (например, []), компилятор вполне может просто выполнить функцию только один раз и используйте результат этого во всех местах, где функция получила "вызов". Ваш "скрытый" отпечаток будет выполнен только один раз, даже если вы вызывали функцию в нескольких местах.

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

Как вы, возможно, уже знаете, Haskell-это "чистый" функциональный язык программирования. По этой причине побочные эффекты (такие как печать значения на экране) не являются случайными, как в более распространенных языках. Этот факт дает Хаскеллу много хороших свойств, но вы будете прощены за то, что не заботитесь об этом, когда все, что вы делаете, это пытаетесь напечатать значение на экране.

Поскольку язык не имеет прямой возможности вызывать побочные эффекты, стратегия заключается в том, что функции могут создайте одно или несколько значений "IO action". Действие ввода-вывода инкапсулирует некоторый побочный эффект (печать на консоль, запись в файл и т. д.) наряду с возможным созданием ценности. Ваша функция dot производит именно такое действие. Проблема, которая у вас сейчас есть, заключается в том, что вам нужно что-то, что сможет вызвать побочный эффект ввода-вывода, а также развернуть значение и, возможно, передать его обратно в вашу программу.

Не прибегая к хакам, это означает, что вам нужно получить ваши действия ввода-вывода) вернитесь к функции main. Практически это означает, что все между main и dot должно быть в "ИО монаде". То, что происходит в" ИО монаде", остается, так сказать, в" ИО монаде".

EDIT

Вот самый простой пример, который я могу себе представить для использования вашей функции dot в допустимой программе Хаскелла:

module Main where

main :: IO ()
main =
    do
        let xs = [2,3,4]
        xr <- dot xs
        xrr <- dot xr
        return ()

dot (x:xs) =
    do
        print x
        return xs