where proxy :: Stream n a -> n
proxy = undefined
В этом случае мы пишем:
{-# Language ScopedTypeVariables #-}
...
dt :: forall n. (Nat n, Fractional a) => Stream n a -> a
dt xs = 1 / (fromIntegral $ toInt (undefined :: n))
Обратите внимение на появление forall в определении типа. Попробуйте скомпилировать пример без
него или переместите его в другое место. Во многих случаях применения этого рсширения можно избежать
с помощью стандартной функции asTypeOf, посмотрим на определение из Prelude:
asTypeOf :: a -> a -> a
asTypeOf x y = x
Фактически это функция const, оба типа которой одинаковы. Она часто используется в инфиксной форме
для фиксации типа первого аргумента:
q = f $ x ‘asTypeOf‘ var
Получается очень наглядно, словно это предложение обычного языка.
И другие удобства и украшения
Стоит упомянуть несколько расширений. Они лёгкие для понимания, в основном служат украшению
записи или для сокращения рутинного кода.
Директива deriving может использоваться только с несколькими стандартными классами, но если мы
определили тип-обёртку через newtype или просто синоним, то мы можем очень просто определить новый
тип экземпляром любого класса, который доступен завёрнутому типу. Как раз для этого существует расши-
рение GeneralizedNewtypeDeriving:
newtype MyDouble = MyDouble Double
deriving (Show, Eq, Enum, Ord, Num, Fractional, Floating)
Мы говорили о том, что обычные числа в Haskell перегружены, иногда возникает необходимость в пе-
регруженных строках, как раз для этого существует расширение OverloadedStrings. При этом за обычной
записью строк может скрываться любой тип из класса:
class IsString a where
fromString :: String -> a
Расширение TypeOperators позволяет определять инфиксные имена не только для конструкторов типов,
но и для самих типов, синонимов типов и даже классов:
data a :+: b = Left a | Right b
17.3 Краткое содержание
В этой главе мы затронули малую часть возможностей, которые предоставляются системой ghc. Haskell
является полигоном для испытания самых разнообразных идей. Это экспериментальный язык. Но в практиче-
ских целях в 1998 году был зафиксирован стандарт языка, его обычно называют Haskell98. Любое расшире-
ние подключается с помощью специальной прагмы Language. Новый стандарт Haskell Prime включит в себя
наиболее устоявшиеся расширения. Также мы рассмотрели несколько полезных классов и синтаксических
конструкций, которые, возможно, облегчают написание программ.
17.4 Упражнения
Это была справочная глава, присмотритесь к рассмотренным возможностям и подумайте какие нужны
вам, а какие нет. Возможно вы вовсе не будете ими пользоваться, но некоторые из них могут встретиться
вам в чужом коде или в библиотеках.
264 | Глава 17: Дополнительные возможности
Глава 18
Средства разработки
В этой главе мы познакомимся с основными средствами разработки больших программ. Мы научимся
устанавливать и создавать библиотеки, писать документацию.
18.1 Пакеты
В Haskell есть ещё один уровень организации данных, мы можем объединять модули в пакеты (package).
Также как и модули пакеты могут зависеть от других пакетов, если они пользуются модулями их этих па-
кетов. Одним пакетом мы уже пользовались и довольно часто, это пакет base, который содержит все стан-
дартные модули, например такие как Prelude, Control.Applicative или Data.Function. Для создания и
установки пакетов существует приложение cabal. Оно определяет протокол организации и распростране-
ния модулей Haskell.
Создание пакетов
Предположим, что мы написали программу, которая состоит из нескольких модулей. Пусть все модули
хранятся в директории с именем src. Для того чтобы превратить набор модулей в пакет, нам необходимо
поместить в одну директорию с src два файла:
• имяПакета. cabal – файл с описанием пакета.
• Setup. hs – файл с инструкциями по установке пакета
.cabal
Посмотрим на простейший файл с описанием библиотеки, этот файл находится в одной директории с
той директорией, в которой содержатся все модули приложения и имеет расширение . cabaclass="underline"
Name
: Foo
Version