2.2.2 Списки
Списки записываются в виде [e1, ..., ek], где k>=1. Конструктором списка является :, пустой список обозначается []. Стандартные операции над списками описаны в Prelude:
Функция head возвращает первый элемент списка.
Функция last возвращает последний элемент списка.
Функция tail возвращает список без первого элемента
Функция init возвращает список без последнего элемента
Функция null проверяет список на пустоту. Если в качестве аргумента этой опера-ции будет задан пустой список, то функция выдаст значение True, в противном случае - False
Функция length возвращает длину списка.
Функция elem проверяет наличие элемента в списке.
Функция take возвращает список, состоящий из n первых элементов исходного списка.
Функция zip возвращает список, состоящий из пар объединенных исходных списков.
Функция !! возвращает элемент, номер которого задан (начиная с 0).
Функции head и tail определены для непустых списков. При попытке применить их к пустому списку интерпретатор сообщает об ошибке.
2.2.3 Do – выражение
exp -> do { stmts } (do-выражение)
stmts -> stmt1 ... stmtn exp [;] (n>=0)
stmt -> exp ;
| pat <- exp ;
| let decls ;
| ; (пустая инструкция)
Перевод:
выражение -> do { список-инструкций } (do-выражение)
список-инструкций -> инструкция1 ... инструкцияn выражение [;] (n>=0)
инструкция -> выражение ;
| образец <- выражение ;
| let список-объявлений ;
| ; (пустая инструкция)
Do-выражения предоставляют более удобный синтаксис для монадического программирования. Оно позволяет записать такое выражение
putStr "x: " >>
getLine >>= \l ->
return (words l)
в более традиционном виде:
do putStr "x: "
l <- getLine
return (words l)
Трансляция:
Для do-выражений выполняются следующие тождества, которые, после удаления пустых stmts, можно использовать в качестве трансляции в ядро:
do {e} =e
do {e;stmts} =e >> do {stmts}
do {p <- e; stmts} =let ok p = do {stmts}
ok _ = fail "..."
in e >>= ok
do {let decls; stmts} =let decls in do {stmts}
Пропуски "..." обозначают генерируемое компилятором сообщение об ошибке, передаваемое функции fail, желательно давая некоторое указание на местоположение ошибки сопоставления с образцом; функции >>, >>= и fail являются операциями в классе Monad, определенными в Prelude; ok является новым идентификатором.
Как показано в трансляции do, переменные, связанные let, имеют полностью полиморфные типы, тогда как те переменные, которые определены с помощью <-, являются связанными лямбда-выражением и поэтому являются мономорфными.
2.3 Монада ввода/вывода
2.3.1.Функции ввода
Эти функции считывают данные из стандартного устройства ввода (обычно это пользовательский терминал).
getChar :: IO Char
getLine :: IO String
getContents :: IO String
interact :: (String -> String) -> IO ()
readIO :: Read a => String -> IO a
readLn :: Read a => IO a
Операция getChar вызывает исключение при появлении признака конца файла, a предикат isEOFError, который распознает это исключение, определен в библиотеке IO. Операция getLine вызывает исключение при тех же обстоятельствах, что и hGetLine, определенная в библиотеке IO.
Операция getContents возвращает весь пользовательский ввод в виде одной строки, которая считывается лениво, по мере надобности. Функция interact принимает в качестве аргумента функцию типа String->String. Весь ввод из стандартного устройства ввода передается этой функции в качестве аргумента, а результирующая строка выводится на стандартное устройство вывода.
Обычно операция read из класса Read используется для преобразования строки в значение. Функция readIO похожа на read, за исключением того, что она предупреждает монаду ввода - вывода об ошибке разбора вместо завершения программы. Функция readLn объединяет getLine и readIO.
2.3.2 Функции вывода
Эти функции записывают в стандартное устройство вывода (обычно это пользовательский терминал).
putChar :: Char -> IO ()
putStr :: String -> IO ()
putStrLn :: String -> IO () -- добавляет символ новой строки
print :: Show a => a -> IO ()
Функция print выводит значение любого пригодного для печати типа на стандартное устройство вывода. Пригодные для печати типы --- это те типы, которые являются экземплярами класса Show; print преобразует значения в строки для вывода, используя операцию show, и добавляет символ новой строки.
2.3.3 Обработка исключений
Что делать, если в процессе операций ввода/вывода возникла неординарная ситуация? Например, функция getChar обнаружила конец файла. В этом случае произойдет ошибка. Haskell предлагает для этих целей механизм обработки исключений. Для этого не используется какой-то специальный синтаксис, но есть специальный тип IOError, который содержит описания всех возникаемых в процессе ввода/вывода ошибок.
Обработчик исключений имеет тип (IOError -> IO a), при этом функция catch ассоциирует (связывает) обработчик исключений с набором действий:
catch:: IO a -> (IOError -> IO a) -> IO a
Аргументами этой функции являются действие (первый аргумент) и обработчик исключений (второй аргумент). Если действие выполнено успешно, то просто возвращается результат без возбуждения обработчика исключений.
Если же в процессе выполнения действия возникла ошибка, то она передается обработчику исключений в качестве операнда типа IOError, после чего выполняется сам обработчик.
0 комментариев