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

Сон в Хаскелле

Я видел, что у Haskell есть функция сна, называемая "delay": Control.Concurrent.Thread.Delay

Мой вопрос: если Haskell является чисто функциональным, как можно иметь такую ​​вещь? Является ли сон побочным эффектом или я что-то не хватает?

4b9b3361

Ответ 1

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

Мне просто кажется, что это самое простое и крутое объяснение.

Притворная приманка

Haskell - чисто функциональный язык. Это должно означать, что оценка программы Haskell должна всегда давать одинаковые результаты. Однако это не похоже на это! Посмотрите на что-то вроде

-- Echo.hs
main :: IO ()
main = getLine >>= putStrLn

Кажется, что это делает что-то другое в зависимости от пользовательского ввода.

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

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

Злоумышленники

На самом деле это не так! Соответствующая ментальная модель представляет собой IO как нечто вроде

data IO a = PutStrLn String a
          | GetLine (String -> a)
          ...

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

Это не просто незначительный семантический каламбур, хотя мы можем сделать что-то вроде

runBackwards :: [IO ()] -> IO ()
runBackwards  = foldr (>>) (return ()) . reverse

Другими словами, мы можем манипулировать нашими "планами" как нормальные значения первого класса.

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

В некотором смысле вы можете почти просмотреть программу Haskell в качестве окончательной формы метапрограммирования, создавая программы "на лету" во время выполнения и оценивая их каким-то интерпретатором.

Итак, когда вы говорите

 foo = delay 20

Вы не говорите: "Задержите эту программу на 20 ударов", вы говорите: "В программе, которую этот код строит, приостановите его выполнение на 20 ударов при запуске".

Кто заботится

Справедливо спросить "Кто заботится": если этот код запускается в какой-то момент, кто заботится о том, кто его запускает? Что хорошего делает, чтобы быть чисто функциональным таким образом? На самом деле он может иметь некоторые интересные эффекты (хе).

Например, подумайте о чем-то вроде http://www.tryhaskell.org, очевидно, что ему нужно запустить код Haskell, но он также не может просто вслепую выполнить любое IO it становись! Что он может сделать, так это предоставить другую реализацию IO, показывая идентичный API.

Этот новый IO создает красивое дерево, такое как datastructure, которое может быть легко дезинфицировано и проверено веб-сервером, чтобы гарантировать, что он никогда не запускает что-то злое. Мы даже можем скомпилировать нашу структуру fake-IO с нормальной, которую GHC обеспечивает и эффективно выполняет на сервере! Поскольку в них никогда не бывает ничего плохого, мы должны только доверять коду, который мы написали.

Больше нет бесконечных дырок в стиле апплета. Заменяя IO, мы знаем вне тени сомнения, что мы можем выполнить этот код, и он никогда не попытается сделать что-то злое.

Злые переводчики повсюду

На самом деле, это понятие построения структур данных полезно не только для IO. Это отличный способ структурировать любой проект, целью которого является предоставление ограниченного DSL. Что-нибудь из

  • Язык запросов
  • Сценарии игр
  • Генерация кода
  • Написание "клиентской стороны haskell"

Все это можно решить путем создания нормальных структур данных и "компиляции" их на соответствующий язык. Обычным трюком для этого является использование свободной монады . Если вы промежуточный Haskeller, узнайте о em!

Ответ 2

"Чистофункциональный" - интересный термин.

Все, что нужно иметь дело с реальным миром, не является чисто функциональным при первом взгляде. Но почему-то Хаскелу нужно иметь дело с реальным миром. В противном случае язык не имеет смысла.

Таким образом, решение является монадой IO. Здесь я не буду подробно останавливаться (я уверен, вы можете найти другое объяснение монады IO). Мода IO является примерно функцией с типом RealWorld -> RealWorld.

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

Трюк с delay заключается в том, что мы берем текущий мир и создаем еще один, где время увеличивается на заданное количество секунд.

Ответ 3

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