Изучай Haskell во имя добра! (Липовача) - страница 94

Итак, реализуя функцию, которая принимает имя и номер телефона и проверяет, есть ли такая комбинация в нашей записной книжке, мы можем дать ей красивую и понятную декларацию типа:

>inPhoneBook :: Name –> PhoneNumber –> PhoneBook –> Bool

>inPhoneBook name pnumber pbook = (name,pnumber) `elem` pbook

Если бы мы не использовали синонимы типов, тип нашей функции был бы >String –> String –> [(String,String)] –> Bool. В этом случае декларацию функции легче понять при помощи синонимов типов. Однако не надо перегибать палку. Мы применяем синонимы типов для того, чтобы описать, как используются существующие типы в наших функциях (таким образом декларации типов лучше документированы), или когда мы имеем дело с длинной декларацией типа, которую приходится часто повторять (вроде >[(String,String)]), причём эта декларация обозначает что-то более специфичное в контексте наших функций.

Параметризация синонимов

Синонимы типов также могут быть параметризованы. Если мы хотим задать синоним для ассоциативного списка и при этом нам нужно, чтобы он мог принимать любые типы для ключей и значений, мы можем сделать так:

>type AssocList k v = [(k,v)]

Функция, которая получает значение по ключу в ассоциативном списке, может иметь тип >(Eq>k)>=>>k>–>>AssocList>k>v>–>>Maybe>v. Тип >AssocList – это конструктор типов, который принимает два типа и производит конкретный тип, например >AssocList>Int>String.

Мы можем частично применять функции, чтобы получить новые функции; аналогичным образом можно частично применять типы-параметры и получать новые конструкторы типов. Так же, как мы вызываем функцию, не передавая всех параметров для того, чтобы получить новую функцию, мы будем вызывать и конструктор типа, не указывая всех параметров, и получать частично применённый конструктор типа. Если мы хотим получить тип для отображений (из модуля >Data.Map) с целочисленными ключами, можно сделать так:

>type IntMap v = Map Int v

или так:

>type IntMap = Map Int

В любом случае конструктор типов >IntMap принимает один параметр – это и будет типом, в который мы будем отображать >Int.

И вот ещё что. Если вы попытаетесь реализовать этот пример, вам потребуется произвести квалифицированный импорт модуля >Data.Map. При квалифицированном импорте перед конструкторами типов также надо ставить имя модуля. Таким образом, мы бы записали: >IntMap = Map.Map Int.

Убедитесь, что вы понимаете различие между конструкторами типов и конструкторами данных. Если мы создали синоним типа >IntMap или >AssocList, это ещё не означает, что можно делать такие вещи, как >AssocList [(1,2),(4,5),(7,9)]