Учебник по Haskell | страница 56
ленно сверьтесь с правилом применения в каждом из слагаемых.
Специализация типов при подстановке
Мы говорили о том, что тип аргумента функции и тип подставляемого значения должны совпадать, но
на самом деле есть и другая возможность. Тип аргумента или тип значения могут быть полиморфными. В
этом случае происходит специализация общего типа. Например, при выполнении выражения:
*Nat> Succ Zero + Zero
Succ (Succ Zero)
Происходит специализация общей функции (+) :: Num a => a -> a -> a до функции (+) :: Nat ->
Nat -> Nat, которая определена в экземпляре Num для Nat.
Проверка типов с контекстом
Предположим, что у функции f есть контекст, который говорит о том, что первый аргумент принадлежит
некоторому классу f :: C a => a -> b, тогда значение, которое мы подставляем в функцию, должно быть
экземпляром класса C.
Для иллюстрации давайте попробуем сложить логические значения:
*Nat Prelude> True + False
< interactive>:11:6:
No instance for (Num Bool)
arising from a use of ‘+’
Possible fix: add an instance declaration for (Num Bool)
In the expression: True + False
In an equation for ‘it’: it = True + False
Компилятор говорит о том, что для типа Bool не
определён экземпляр для класса Num.
Проверка типов | 51
No instance for (Num Bool)
Запишем это в виде правила:
f :: C a => a -> b,
x :: T, instance C T
-----------------------------------------
(f x) :: b
Важно отметить, что x имеет конкретный тип T. Если x – значение, у которого тип с параметром, компиля-
тор не сможет определить для какого типа конкретно мы хотим выполнить применение. Мы будем называть
такую ситуацию неопределённостью:
x :: T a => a
f :: C a => a -> b
f x :: ??
-- неопределённость
Мы видим, что тип x, это какой-то тип, одновременно принадлежащий и классу T и классу C. Но мы не
можем сказать какой это тип. У этого поведения есть исключение: по умолчанию числа приводятся к Integer,
если они не содержат знаков после точки, и к Double – если содержат.
*Nat Prelude> let f = (1.5 + )
*Nat Prelude> :t f
f :: Double -> Double
*Nat Prelude> let x = 5 + 0
*Nat Prelude> :t x
x :: Integer
*Nat Prelude> let x = 5 + Zero
*Nat Prelude> :t x
x :: Nat
Умолчания определены только для класса Num. Для этого есть специальное ключевое слово default. В
рамках модуля мы можем указать какие типы считаются числами по умолчанию. Например, так (такое умол-
чание действует в каждом модуле, но мы можем переопределить его):
default (Integer, Double)
Работает правило: если произошла неопределённость и один из участвующих классов является