True
=> False
inv False
+ False
=>
(not False) + False=> True
+ False
=>
and TrueFalse
=> False
Проверять свойства очень важно, потому что другие люди, читая ваш код и используя ваши функции,
будут на них рассчитывать.
20 | Глава 1: Основы
1.6 Ядро Haskell
Фуууухх. Мы закончили наш пробег. Теперь можно остановиться, отдышаться и подвести итоги. Давайте
вспомним синтаксические конструкции, которые нам встретились.
Модули
module New
(edef1, edef2, ... , edefN) whereimport Old1
(idef11, idef12, ... , idef1N)import Old2
(idef21, idef22, ... , idef2M)...
import OldK
(idefK1, idefK2, ... , idefKP)-- определения :
...
Ключевые слова: module
, where, import. Мы определили модуль с именем New, который экспортируетопределения edef1, edef2, … , edefN. И импортирует определения из модулей Old1
, Old2, и т.д., определениянаписаны в скобках за ключевыми словами import
и именами модулей.Типы
Тип определяется с помощью:
• Перечисления альтернатив через |
data Type = Alt1 | Alt2 | ... | AltN
Эту операцию называют
• Составления сложного типа из подтипов, пишем конструктор первым, затем через пробел подтипы:
data Type = Name
Sub1
Sub2
...
SubN
Эту операцию называют
Есть одно исключение: если тип состоит из двух подтипов, мы можем дать конструктору символьное
(а не буквенное) имя, но оно должно начинаться с двоеточия :
, как в случае списка, например, можноделать такие определения типов:
data Type = Sub1 :+ Sub2
data Type = Sub1 :| Sub2
• Комбинации суммы и произведения типов:
data Type = Name1
Sub11
Sub12
...
Sub1N
| Name2
Sub21
Sub22
...
Sub2M
...
| NameK
SubK1
SubK2
...
SubKP
Такие типы называют
тия и способы их комбинирования.
Значения
Как это ни странно, нам встретилась лишь одна операция создания значений:
пишется так
name x1
x2 ...
xN = Expr1name x1
x2 ...
xN = Expr2name x1
x2 ...
xN = Expr3Слева от знака равно стоит составное имя, а справа от знака равно некоторое выражение, построенное
согласно типам. Разные комбинации имени name с параметрами определяют разные уравнения для синонима
name.
Также мы видели символ _
, который означает “всё, что угодно” на месте аргумента. А также мы увидели,как с помощью переменных можно перетаскивать значения из аргументов в результат.
Ядро Haskell | 21
Классы типов
Нам встретилась одна конструкция определения классов типов:
class Name
a wheremethod1 ::
a -> ...method2 ::
a -> ......
methodN ::
a -> ...Экземпляры классов типов
Нам встретилась одна конструкция определения экземпляров классов типов:
instance Name Type where
method1 x1 ...
xN = ...method2 x1 ...
xM = ......
methodN x1 ...
xP = ...Типы, значения и классы типов
Каждое значение имеет тип. Значение v имеет тип T
на Haskell:v :: T
Функциональный тип обозначается стрелкой: a ->
bfun ::
a -> bТип значения может иметь контекст, он говорит о том, что параметр должен принадлежать классу типов:
fun1 :: С
a=>
a -> afun2 ::
(C1 a, C2, ... , CN) => a -> aСуперклассы
Также контекст может быть и у классов, запись
class A
a => B a where...
Означает, что класс B
целиком содержится в A, и перед тем как объявлять экземпляр для класса B, необ-ходимо определить экземпляр для класса A
. При этом класс A называют суперклассом для B.1.7 Двумерный синтаксис
Наверное вы обратили внимание на то, что в Haskell нет разделителей строк и дополнительных скобок,
которые бы указывали границы определения классов или функций. Компилятор Haskell ориентируется по
переносам строки и отступам.
Так если мы пишем в классе:
class Eq
a where(==
) :: a -> a -> a(/=
) :: a -> a -> aПо отступам за первой строкой определения компилятор понимает, что класс содержит два метода. Если
бы мы написали:
class Eq
a where(==
) :: a -> a -> a(/=
) :: a -> a -> a22 | Глава 1: Основы
То смысл был бы совсем другим. Теперь мы определяем класс Eq
с одним методом == и указываем типнекоторого значения (/=
). Основное правило такое: конструкции, расположенные на одном уровне, вырав-ниваются с помощью отступов. Чем правее находится определение, тем глубже оно вложено в какую-нибудь
специальную конструкцию. Пока нам встретилось лишь несколько специальных конструкций, но дальше
появятся и другие. Часто отступы набираются с помощью табуляции. Это удобно. Но лучше пользоваться
пробелами или настроить ваш любимый текстовый редактор так, чтобы он автоматически заменял табуля-