52700.fb2
Parsec. С этим ограничением приходится писать огромные объявления типов для крохотных выражений.
Что-то вроде:
fun :: (Stream s m t, Show t) => ParsecT s u m a -> ParsecT s u m [a]
fun = g . h (q x) y
И так для любого выражения. В этом случае лучше просто выключить ограничение, добавив в начало
файла:
{-# Language NoMonomorphismRestriction #-}
Полиморфизм высших порядков
Когда мы говорили об ST нам встретилась функция с необычным типом:
runST :: (forall s. ST s a) -> a
Слово forall обозначает для любых. Любой полиморфный тип в Haskell подразумевает, что он определён
для любых типов. Например, когда мы пишем:
reverse :: [a] -> [a]
map
:: (a -> b) -> [a] -> [b]
На самом деле мы пишем:
reverse :: forall a. [a] -> [a]
map
:: forall a b. (a -> b) -> [a] -> [b]
262 | Глава 17: Дополнительные возможности
По названию слова forall может показаться, что оно несёт в себе много свободы. Оно говорит о том, что
функция определена для любых типов. Но если присмотреться, то эта свобода оказывается жёстким огра-
ничением. “Для любых” означает, что мы не можем делать никаких предположений о внутренней природе
значения. Мы не можем разбирать такие значения на составляющие части. Мы можем только подставлять
их в новые полиморфные функции (как в map), отбрасывать (как const) или перекладывать из одного ме-
ста в другое (как в swap или reverse). Мы можем немного смягчить ограничение, если укажем в контексте
функции какие классы определены для значений данного типа.
Все стандартные полиморфные типы имеют вид:
fun :: forall a b .. z. Expr(a, b, ... , z)
Причём Expr не содержит forall, а только стрелки и применение новых типов к параметрам. Такой тип
называют полиморфным типом первого порядка (rank). Если forall стоит справа от стрелки, то его можно
вынести из выражения, например, следующие выражения эквивалентны:
fun :: forall a.
a -> (forall b. b -> b)
fun :: forall a b. a -> (b -> b)
Так мы можем привести не стандартный тип к стандартному. Если же forall встречается слева от стрел-
ки, как в функции runST, то его уже нельзя вынести. Это приводит к повышению порядка полиморфизма.
Порядок полиморфизма определяется как самый максимум среди всех подвыражений, что стоят слева от
стрелки плюс один. Так в типе
runST :: (forall s. ST s a) -> a
Слева от стрелки стоит тип первого порядка, прибавив единицу, получим порядок для всего выражения.
Если вдруг нам захочется воспользоваться такими типами, мы можем включить одно из расширений:
{-# Language Rank2Types #-}
{-# Language RankNTypes #-}
В случае рангов произвольного порядка алгоритм вывода типов может не завершиться. В этом случае нам
придётся помогать компилятору расставляя типы сложных функций вручную.
Лексически связанные типы
Мы уже привыкли к тому, что когда мы пишем
swap :: (a, b) -> (b, a)