Jump to content
Main menu
Main menu
move to sidebar
hide
Navigation
Haskell
Wiki community
Recent changes
Random page
HaskellWiki
Search
Search
Create account
Log in
Personal tools
Create account
Log in
Pages for logged out editors
learn more
Contributions
Talk
Editing
Ru/IO Inside
(section)
Page
Discussion
English
Read
Edit
View history
Tools
Tools
move to sidebar
hide
Actions
Read
Edit
View history
General
What links here
Related changes
Special pages
Page information
Warning:
You are not logged in. Your IP address will be publicly visible if you make any edits. If you
log in
or
create an account
, your edits will be attributed to your username, along with other benefits.
Anti-spam check. Do
not
fill this in!
== Добро пожаловать в Реальный мир, детка :) == Почему бы нам не смотреть на '''''Реальный мир''''', как на ещё один тип данных? Назовём этот тип 'RealWorld'. Функция 'main' имеет следующий тип: <haskell> main :: RealWorld -> ((), RealWorld) </haskell> вместо нашего Int используется фиктивный тип 'RealWorld'. Реальный мир похож на эстафетную палочку: когда main вызывает другие функции, в результате которых присутствует IO, main передаёт полученный им '''''мир''''' этим функциям. Все функции, выполняющие ввод-вывод, имеют тип, схожий с типом 'main'. А конкретнее, сам класс типов "IO" определён как синоним типа: <haskell> type IO a = RealWorld -> (a, RealWorld) </haskell> Таким образом, 'main' имеет тип "IO ()", 'getChar' имеет тип "IO Char" и так далее. Например, "IO Char" можно понимать таким образом: получить мир, (может быть, изменить мир) и вернуть Char и изменённый мир. Так выглядит 'main', вызывающий 'getChar' последовательно два раза: <haskell> getChar :: RealWorld -> (Char, RealWorld) main :: RealWorld -> ((), RealWorld) main world0 = let (a, world1) = getChar world0 (b, world2) = getChar world1 in ((), world2) </haskell> 'main' отдаёт первому 'getChar' полученный мир. Возвращённый первым 'getChar' мир отдаётся второму 'getChar'. 'main' возвращает тот мир, который был возвращён вторым 'getChar'. К чему привела такая схема вызова 'getChar'? # Можно ли опустить вызов 'getChar', если его результат не нужен? Нет, так как нам всё равно нужен новый 'RealWorld', возвращаемый 'getChar' помимо символа. # Можно ли переставить местами вызовы 'getChar'? Нет, так как второй 'getChar' использует 'RealWorld', возвращённый первым. # Is it possible to duplicate calls? In Haskell semantics - yes, but real compilers never duplicate work in such simple cases (otherwise, the programs generated will not have any speed guarantees). (Непонятно, что понимается под duplicate calls --[[User:Beroal|Beroal]] 00:48, 18 April 2008 (UTC)) Повторим ещё раз, что 'RealWorld' похож на эстафетную палочку, которая передаётся между IO-процедурами. IO-процедуры, явно или неявно, вызываются из 'main' в строгом порядке. Внутри IO-процедуры 'RealWorld' используется таким образом: чтобы «вычислить» новое значение 'RealWorld', мы выполняем императивные команды. Поэтому каждая IO-процедура выполняется именно в тот момент, который мы задали (момент относительно других IO-процедур). Пример: <haskell> main = do a <- ask "What is your name?" b <- ask "How old are you?" return () ask s = do putStr s readLn </haskell> Теперь вы знаете, как транслировать императивные программы на Хаскелле в низкоуровневый код и можете проверить, что IO-процедуры выполняются именно в том порядке и с теми аргументами, которые вы запланировали. Пока мы рассматривали линейные алгоритмы. Можно ли задать ветвление? Конечно. Так задаётся управляющая структура 'when': <haskell> when :: Bool -> IO () -> IO () when condition action world = if condition then action world else ((), world) </haskell> Мы можем выполнить некоторую IO-процедуру при некотором условии, наложенном на аргумент функции 'when'. Если аргумент 'condition' ложный, то 'action' не будет вызвана, так как реальный компилятор не вызывает функцию, если её результат не нужен для подсчёта окончательного результата (под окончательным подразумевается значение 'RealWorld', возвращаемое 'main'). (Чтобы обеспечить правильное выполнение императивных команд, недостаточно, чтобы 'RealWorld' был абстрактным типом. Значение типа 'RealWorld' (то есть, реальный мир) необходимо запретить копировать. Если компилятор нарушит вышеприведённое условие, то есть, вычислит 'action' при ложном 'condition', то одно и то же значение типа 'RealWorld' будет передано в 'action' возвращено функцией 'when'. То есть компилятор должен уметь копировать мир. Но скопировать мир нельзя, так как под миром подразумеваются не только внутренности компьютера, но и все его внешние устройства, то есть, потенциально, вся Вселенная. То есть, 'RealWorld' — это не обычный тип. Этот тип обозначает данные, которые нельзя копировать. Это свойство 'RealWorld' можно распространить на другие типы данных, например, можно задать монолитный массив, который запрещено копировать из соображений производительности. Подробнее с некопируемыми данными можно познакомиться в функциональном языке Clean, uniqueness type system.) Аналогично можно задать циклы и другие управляющие конструкции. Это вам домашнее задание. Наконец возникает опасение, что протаскивание 'RealWorld' через все функции увеличит накладные расходы. На самом деле, компилятор, видя, что 'RealWorld' не содержит данных (так же, как и "()"), не включает 'RealWorld' в низкоуровневый императивный код. Круто? :)
Summary:
Please note that all contributions to HaskellWiki are considered to be released under simple permissive license (see
HaskellWiki:Copyrights
for details). If you don't want your writing to be edited mercilessly and redistributed at will, then don't submit it here.
You are also promising us that you wrote this yourself, or copied it from a public domain or similar free resource.
DO NOT SUBMIT COPYRIGHTED WORK WITHOUT PERMISSION!
Cancel
Editing help
(opens in new window)
Toggle limited content width