Uploaded by Илья Шмаровоз

Функциональное программирование. Haskell. Лекция 1

advertisement
Функциональное
программирование
Лекция 1. Введение в функциональное
программирование. Язык Haskell
ФП – это:
1)Программирование, в котором нет побочных эффектов, в том числе
традиционного присваивания. Единственным «эффектом» выполнения
любой функции является вычисленный результат. (Редкие исключения.)
2)Поскольку нет присваиваний, переменные, получив значение в начале
блока вычислений, никогда его не меняют. (Переменные – просто
сокращенная запись выражений.)
3)Не явного управления последовательностью выполнения
операций. (Отсутствие побочных эффектов ведет к тому, что порядок
проведения вычислений становится менее важен, поскольку на
результат не влияют побочные эффекты, не важно, когда его
вычислять.)
2
ОСОБЕННОСТИ ЯЗЫКА HASKELL
Язык Haskell - это чисто функциональный язык
программирования.
В императивных языках результат достигается при передаче
компьютеру последовательности команд, которые он затем
выполняет. При этом компьютер может изменять своё
состояние.
Например, можно установить переменную а равной 5,
производим какое-либо действие, а затем меняем её значение.
Кроме того, есть управляющие инструкции, позволяющие
повторять несколько раз определённые действия, такие как
циклы for и while.
В чисто функциональных языках не говорится, как делать те
или иные вещи, – скорее говорится, что представляет собой
проблема.
3
• Haskell – ленивый язык. Это означает, что он не будет
выполнять функции и производить вычисления, пока это
действительно не потребовалось для вывода результата
(если иное не указано явно).
• Haskell проделает минимум вычислений, достаточных
для их отображения. Ленивость позволяет создавать
бесконечные структуры данных, потому что реально
вычислять требуется только ту часть структуры данных,
которую необходимо отобразить.
• Язык Haskell – статически типизированный язык. Когда
компилируется программа, то компилятор знает, какой
кусок кода – число, какой – строка и т. д. Это означает, что
множество возможных ошибок будет обнаружено во время
компиляции. Если, скажем, необходимо сложить вместе
число и строку, то компилятор «пожалуется».
4
• В Haskell есть очень хорошая система типов, которая
умеет автоматически делать вывод типов.
• Это означает, что не нужно описывать тип в каждом
куске кода, потому что система типов может
вычислить это сама.
• Если, скажем, a=5 + 4, то нет необходимости
говорить, что а – число, так как это может быть
выведено автоматически. Вывод типов делает ваш код
более универсальным.
• Если функция принимает два параметра и
складывает их, а тип параметров не задан явно, то
функция будет работать с любыми двумя параметрами,
которые ведут себя как числа.
5
• Haskell – ясный и выразительный язык, потому что
он использует множество высокоуровневых идей;
программы обычно короче, чем их императивные
эквиваленты, их легче сопровождать, в них меньше
ошибок.
6
• Для начала работы Haskell понадобятся текстовый
редактор и компилятор Haskell.
• На сегодняшний день самым популярным компилятором
Haskell является GНС (Glаsgоw Наsкеll Соmpilеr), который и
будет использоваться в примерах. Проще всего
обзавестись им, скачав Haskell Platform, которая включает,
помимо прочего, ещё и массу полезных библиотек.
• Для получения Haskell Platform нужно зайти на сайт
http://hackage.haskell.org/platform/ и далее следовать
инструкциям по вашей операционной системе.
Еще ссылки : https://downloads.haskell.org/~platform/
7
Для того чтобы изучать среду программирования первую очередь нужно установить
его среду разработки.
Для язык haskell такой средой разработки служит Haskell Platform.
В состав Haskell Platform входит компилятор :
– Glasgow Haskell Compiler (GHC):
– GHCi - интерактивный интерфейс к компилятору Glasgow Haskell
Compiler (GHCi часто называют интерпретатором и далее мы тоже будем
его использовать.
– WinGHCi – тот же интерпретатор, но с оконным интерфейсом.
– И также набор инструментов связанных с отладкой.
Исходный код на языке haskell сохраняется в обычных текстовых
файлах с расширением hs.
В состав Haskell Platform платформ не входит редактор исходного кода
Вы можете пользоваться любым текстовым редактором который
поддерживает подсветку синтаксиса Haskell
8
ОСНОВЫ РАБОТЫ С WinGHCi
• После запуска WinGHCi на экране появляется диалоговое
окно, автоматически загружается специальный файл
предопределений типов и определений стандартных
функций на языке Haskell (Prelude.hs) и выводится
стандартное приглашение к работе.
• Диалоговое окно среды разработчика состоит из
главного меню, набора кнопок для быстрого доступа к
наиболее часто используемым командам и консоли, где
происходит работа с интерпретатором.
• Система не позволяет создавать и редактировать файлы
с кодами программ, для этого требуется использование
любого текстового редактора, поддерживающего
обычный стандарт TXT (этим редактором, например,
может быть стандартный блокнот Windows).
9
• Загрузка модулей из внешних файлов. Позволяет
выбрать и открыть файл, из которого загружаются все
модули, обнаруживаемые интерпретатором в этом
файле.
• Вырезать выделенный текст. Стандартная функция
редактирования текстов. Удаляет из редактора
выделенный текст и помещает его в буфер обмена
операционной системы.
• Скопировать выделенный текст в буфер обмена.
Стандартная функция редактирования текстов. Копирует
выделенный текст в буфер обмена операционной
системы.
• Вставить текст из буфера обмена. Стандартная
функция редактирования текстов. Вставляет в
редактируемый тест содержимое буфера обмена
операционной системы.
10
Очистить
выбранный
текст.
Стандартная
функция
редактирования текстов.
Запустить внешний редактор текста. Запускает внешний
текстовый редактор, зарегистрированный в операционной
системе.
Запуск на выполнение выражения «main». Исполняет
функцию main в загруженных модулях (конечно, если такая
функция обнаружена в модулях). Если функция main не
обнаружена ни в одном из загруженных мдулей, то выдаётся
ошибка: ERROR — Undefined variable "main".
Остановка исполнения программы. Остановка выполнения
любой запущенной функции. Используется, например, для
прекращения вычисления бесконечного списка.
Перезагрузка всех файлов текущего проекта. Осуществляет
перезагрузку всех файлов с целью загрузить в память
интерпретатора все сделанные изменения в коде проекта.
11
Установка параметров интерпретатора. Вывод на экран
диалогового окна установки набора параметров
интерпретатора языка Haskell.
Вывод на экран иерархии классов. На экране появляется
иерархия классов текущего проекта, показанная в виде
множества прямоугольников с названиями (классы) и
связей между ними (отношения наследования).
Вызов справки. Вызывает на экран стандартное
диалоговое окно справочной информации.
Выход из программы. Осуществляет выход из WinGHCi в
операционную систему.
12
• Консоль предоставляет небольшой набор служебных
конструкций,
позволяющих
управлять
работой
инструментального средства (ИС). Многие из этих
команд дублируют действия кнопок на панели
инструментов и некоторые пункты главного меню
приложения.
• Каждая команда начинается с символа «двоеточие» —
«:». Это сделано для того, чтобы отличить встроенные
команды от написанных разработчиками функций.
Кроме того, ИС позволяет сокращать каждую команду
вплоть до одной буквы, набрав только символ
«двоеточие» и собственно первую букву команды.
• Всего существует девятнадцать команд, ниже
представлено подробное описание каждой из них
13
Команды консоли WinGHCi
:load [<filenames>]
Загружает программные модули из заданных файлов (имена
файлов можно разделить пробелом).
:also <filenames>
Подгружает дополнительные модули в текущий проект. Имена
файлов должны быть разделены пробелами (если
указывается более чем один файл).
:reload
Повторяет последнюю выполненную команду загрузки (:load).
:project <filename>
Загружает и использует файл проекта. Загрузить можно
только один файл. Файлы проекта используются для
объединения разрозненных файлов с кодом. При повторном
использовании команды происходит выгрузка всех файлов
(как проектных, так и обычных) из памяти интерпретатора.
14
:edit [<filename>]
Вызывает внешний текстовый редактор для исправления
указанного файла. Если имя файла не указано, то на
редактирование вызывается последний файл (загруженный
или редактированный). Данная команда дублирует кнопку
вызова внешнего текстового редактора на панели
инструментов.
:module <module>
Устанавливает заданный модуль в качестве текущего для
выполнения функций. Эта команда предназначена, в первую,
очередь для разрешения коллизий имён.
:type <expr>
Выводит на экран тип заданного выражения. Эта команда
используется, главным образом, в отладочных целях для
быстрого получения типа создаваемого выражения.
:?
Выводит на экран список команд с кратким описанием.
15
:set [<options>]
Позволяет задать параметры ИС с командной строки.
Дублирует действие диалогового окна настройки. Все
возможные параметры этой команды (<options>) выводятся
на экран при выполнении этой команды без каких-либо
параметров.
:names [pat]
Выводит на экран список всех имён объектов, которые
находятся в текущем (если не задано иное) пространстве
имён.
:info <names>
Выводит на экран описание заданных имён объектов.
Например, для функций выводит их тип вместе с именем
заданной функции.
:browse <modules>
Выводит на экран список всех объектов (функций,
переменных, типов), определённых в заданных модулях.
16
:find <name>
Вызывает на редактирование модуль, содержащий заданное
имя.
:!<command>
Выходит в операционную систему и выполняет заданную
команду. Необходимо особо отметить, что между символом
«восклицательный знак» и именем команды операционной
системы должен отсутствовать пробел.
:cd <directory>
Изменяет текущий каталог, с которым работает ИС.
:version
Выводит на экран информацию о версии установленного интерпретатора языка Haskell.
:quit
Осуществляет выход в операционную систему. Дублирует
кнопку на панели инструментов.
17
БАЗОВЫЕ ТИПЫ ЯЗЫКА HASKELL
• В функциональном программировании все
множество величин разделяется на организованные
группы, называемые типами. Целые числами
(integer) . Для работы с дробными числами чаще
всего используется тип Float. Кроме них существуют
еще другие типы чисел (например Int и Double),
логические величины (элементы множества Bool),
символы (элементы множества Char), списки, деревья
и т. д.
• Еще раз отметим важность строгой типизации:
каждое выражение, которое не может быть
ассоциировано с приемлемым типом считается
неверно
сформированным
и
отвергается
компьютером до вычисления.
18
Явное определение типов
Воспользуемся интерпретатором WinGHCi (или GHCi) для определения типов
нескольких выражений. Сделать это можно с помощью команды
:type ( возможно сократить до одной буквы :t )
которая, если за ней следует любое правильное выражение, выдаст нам тип
последнего
Символы :: означают: «имеет тип»
У явно указанных типов первый символ
• Prelude> :t 'Й'
всегда в верхнем регистре. Символ ‘Й', имеет
• 'Й' :: Char
тип Char - это сокращение от «character» –
• Prelude> :t True
символ.
Константа True имеет тип Bool
• True :: Bool
"ДОБРЫЙ ДЕНЬ!" получили [Char].
• Prelude> :t "ДОБРЫЙ ДЕНЬ!"
Квадратные скобки указывают на список –
• "ДОБРЫЙ ДЕНЬ!" :: [Char]
следовательно, перед нами «список
• Prelude> :t 6 == 8
символов»
• 6 == 8 :: Bool
В отличие от списков, каждый кортеж любой
длины имеет свой тип. Так выражение (True,
• Prelude> :t (True, 'a')
• (True, 'a') :: (Bool, Char) 'a') имеет тип (Bool, Char), тогда как
выражение ('a','b','c') будет иметь тип (Char,
Char, Char). Выражение 6==8всегда вернёт
False, поэтому его тип – Bool.
19
Основными типами языка Haskell являются:
–
Типы Integer и Int используется для представления целых чисел, причем
значения типа Integer не ограничены по длине; тип Int представляет
целые числа фиксированной длины.
–
Типы Float и Double используется для представления вещественных
чисел.
–
Тип Bool содержит два значения: True и False, и предназначен для
представления результата логических выражений.
–
Тип Char используется для представления символов. Char – символ Unicode.
Для представления строки используется список значений Char: [Char]
•
Кроме того, вы можете встретить упоминания о некоторых классах – семействах типов,удовлетворяющих
определенным требованиям. Вот некоторые из них:
–
–
–
–
–
Eq – все те типы, значения которых можно проверять на равенство (с
помощью операций (==) и (/=)).
Ord – типы, на множествах значений которых присутствует
отношение порядка, следовательно, их можно сравнивать на «большеменьше».
Num – Числовые константы без точки принадлежат классу типов Num..
Fractional - Числовые константы с точкой принадлежат классу
типов Fractional. К классу типов Fractional относятся типы Double и Float
Integral – типы целых чисел (Integer и Int).
20
Язык Haskell. Значения
Значение - простейшие данные, которые можно понимать как ответ
на какой-то вопрос, как результат вычисления, и которые нельзя
дальше "упростить" или "вычислить".
Например:
5
True 'a'
(1,True)
[1,2,3,4,5]
Значениями НЕ являются:
5+6
x-1
Integer
21
Язык Haskell. Выражения
Выражение - это какая-то конструкция, которую в отличие от
значения
можно «упростить», «редуцировать»:
4+5 → 9
(4+5)*2 → 9*2 → 18
(x-1)^2 + (x+1)^2 → x^2+2*x+1 + x^2-2*x+1 → 2*x^2+2
Выражение может включать в себя как константы, так и
переменные имена. Так же, как и значение, выражение имеет
определенный
неизменный тип.
22
Арифметика
Haskell поддерживает следующие арифметические операторы:
(+), (-), (/), (^), `div`, `mod`.
Причем эти операторы могут быть использованы как:
2 + 2 в привычной инфиксной форме
(+) 2 2
так и в префиксной
!Обратите внимание, что при использовании в префиксной форме
операторов (+),(-), (/), (^), их нужно заключать скобки, а операторы
`div`и `mod`при использовании в инфиксной форме следует
заключать в обратные кавычки (`).
Кроме того, можно использовать стандартные математические функции
sqrt (квадратныйкорень), sin, cos, exp и т.д. В отличие от многих
других языков программирования, вHaskell при вызове функции не
обязательно помещать аргумент в скобки. Таким образом, можно просто
писать sqrt 2, а не sqrt(2)
23
•
•
•
Prelude> exp (-9)
1.2340980408667953e-4
it :: Floating a => a
•
•
•
Prelude> exp (-9) +1
1.0001234098040868
it :: Floating a => a
•
•
•
Prelude> exp ((-9) +1)
3.3546262790251185e-4
it :: Floating a => a
24
Логические операторы
Логические операторы Haskell:
(==), (/=), (&&), (||), (>=), (<=), (>), (<), (not)
Результатом вычисления каждого их них является значение типа Bool.
Аналогично арифметическим операторам, поддерживаются две
формы записи – инфиксная и префиксная.
25
• Список – одна из главных структур данных в функциональных языках. Список –
это потенциально бесконечный упорядоченный набор однотипных элементов.
• [1,3,4,2] :: [Integer] ['П','Р','И','В',’Е',’Т']
:: [Char]
• [[1,2],[],[3,1]] :: [[Integer]]
• Строки являются обычными списками символов (обратите внимание на
вид кавычек):
• "hello" :: Char
• "hello" == ['h','e','l','l','o']
• Кортежи, в отличие от списков, могут содержать фиксированное число
разнотипных элементов.
• (1,'a') :: (Integer, Char)
• (True,1) :: (Bool, Integer)
• ("MARINA",9,[5,5,5]) :: (Char, Integer, [Integer])
26
Списки
• Списки в языке Haskell являются гомогенными структурами данных;
это означает, что в них можно хранить элементы только одного типа.
Можно иметь список целых или список символов, но нельзя получить
список с целыми числами и символами одновременно.
• Списки заключаются в квадратные скобки, а элементы разделяются
запятыми
• Для создания списка перечислите элементы этого списка (обязательно
одного типа) череззапятую, взяв это перечисление в квадратные скобки:
[4,8,15,16,23,42]
27
Интервалы
Интервалы – это способ создания списков, являющихся
арифметическими последовательностями элементов, которые
можно перечислить по порядку: один, два, три, четыре и т. п.
Символы тоже могут быть перечислены: например, алфавит –
это перечень символов от A до Я.
• Чтобы создать список, содержащий все натуральные числа от
1 до 20, достаточно написать [1..20]
•
•
•
Prelude> [15..30]
[15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30]
•
•
Prelude> ['A'..'Z']
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
•
•
•
Prelude> [2,4..10]
[2,4,6,8,10] – все четные числа до 10
Нужно поставить запятую между первыми двумяэлементами
последовательности и указать верхний предел диапазона.
28
▪
▪
▪
▪
▪
▪
▪
▪
▪
•
Функция head возвращает первый элемент списка.
Функция last возвращает последний элемент списка.
Функция tail возвращает список без первого элемента
Функция init возвращает список без последнего элемента
Функция null проверяет список на пустоту. Если в качестве аргумента этой
операции будет задан пустой список, то функция выдаст значение True, в
противном случае - False
Функция length возвращает длину списка.
Функция elem проверяет наличие элемента в списке.
Функция take возвращает список, состоящий из n первых элементов
исходногосписка.
Функция zip возвращает список, состоящий из пар объединенных
исходныхсписков.
Функции head и tail определены для непустых списков. При попытке
применить их к пустому списку интерпретатор сообщает об ошибке
29
30
31
Download