Опубликован: 19.09.2008 | Доступ: свободный | Студентов: 658 / 70 | Оценка: 4.50 / 5.00 | Длительность: 21:25:00
Лекция 8:

Основные операции ввода - вывода

< Лекция 7 || Лекция 8: 12 || Лекция 9 >
Аннотация: В данной лекции рассматривается система ввода-вывода, которая основана на математическом основании, имя которого - монады. Для осуществления ввода-вывода необходимо понять теорию монад. Монадические операторы используются и для других целей, но об этом в другой лекции. А на данном этапе рассмотрим осуществления на языке Haskell ввода-вывода, какие ошибки при этом могут возникнуть. А также затронем тему обработки исключений в монаде ввода-вывода

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

Монада ввода - вывода используется в Haskell как связующее звено между значениями, присущими функциональному языку, и действиями, характеризующими операции ввода - вывода и императивное программирование в общем. Порядок вычисления выражений в Haskell ограничен только зависимостями данных; реализация обладает значительной свободой в выборе этого порядка. Действия, тем не менее, должны быть упорядочены определенным образом для выполнения программы и, в частности, ввода - вывода, для того чтобы быть правильно интерпретированы. В Haskell монада ввода - вывода предоставляет пользователю способ указать последовательное связывание действий, и реализация обязана соблюдать этот порядок.

Термин монада происходит из отрасли математики, известной как теория категорий. Однако, с точки зрения программиста Haskell , лучше думать о монаде как об абстрактном типе данных. В случае монады ввода - вывода абстрактными значениями являются упомянутые выше действия. Некоторые операции являются примитивными действиями, соответствующими обычным операциям ввода - вывода. Специальные операции (методы в классе Monad, см. раздел "6.3.6" ) последовательно связывают действия, соответствующие последовательным операторам (таким как точка с запятой) в императивных языках.

7.1. Стандартные функции ввода - вывода

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

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

Далее, вспомним, что String является синонимом для [Char] (раздел "6.1.2" ).

Функции вывода

Эти функции записывают в стандартное устройство вывода (обычно это пользовательский терминал).

putChar  :: Char -> IO ()
  putStr   :: String -> IO ()
  putStrLn :: String -> IO ()  - добавляет символ новой строки
  print    :: Show a => a -> IO ()

Функция print выводит значение любого пригодного для печати типа на стандартное устройство вывода. Пригодные для печати типы - это те типы, которые являются экземплярами класса Show; print преобразует значения в строки для вывода, используя операцию show, и добавляет символ новой строки.

Например, программа для печати первых 20 целых чисел и их степеней 2 могла быть записана так:

main = print ([(n, 2^n) | n >- [0..19]])

Функции ввода

Эти функции считывают данные из стандартного устройства ввода (обычно это пользовательский терминал).

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 вызывает исключение (раздел "7.3" ) при появлении признака конца файла, a предикат isEOFError, который распознает это исключение, определен в библиотеке IO. Операция getLine вызывает исключение при тех же обстоятельствах, что и hGetLine, определенная в библиотеке IO.

Операция getContents возвращает весь пользовательский ввод в виде одной строки, которая считывается лениво, по мере надобности. Функция interact принимает в качестве аргумента функцию типа String -> String. Весь ввод из стандартного устройства ввода передается этой функции в качестве аргумента, а результирующая строка выводится на стандартное устройство вывода.

Обычно операция read из класса Read используется для преобразования строки в значение. Функция readIO похожа на read, за исключением того, что она предупреждает монаду ввода - вывода об ошибке разбора вместо завершения программы. Функция readLn объединяет getLine и readIO.

Следующая программа просто удаляет все символы, не являющиеся ASCII, из своего стандартного ввода и отображает результат на своем стандартном выводе. (Функция isAscii определена в библиотеке.)

main = interact (filter isAscii)

Файлы

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

Функции writeFile и appendFile соответственно записывают или добавляют в конец строку, свой второй аргумент, в файл, свой первый аргумент. Функция readFile считывает файл и возвращает содержимое файла в виде строки. Файл считывается лениво, по требованию, как в getContents.

type FilePath =  String
  
  writeFile  :: FilePath -> String -> IO ()
  appendFile :: FilePath -> String -> IO ()
  readFile   :: FilePath           -> IO String

Обратите внимание, что writeFile и appendFile записывают литеральную строку в файл. Для того чтобы записать значение любого пригодного для печати типа, как в print, сначала используется функция show для преобразования значения в строку.

main = appendFile "квадраты" (show [(x,x*x) | x >- [0,0.1..2]])
< Лекция 7 || Лекция 8: 12 || Лекция 9 >