Что делает ключевое слово «Forall» в Haskell / GHC?
Вопрос
Я начинаю понимать, как forall
Ключевое слово используется в так называемых «экзистенциальных типах», как это:
data ShowBox = forall s. Show s => SB s
Это только подмножество, однако, как forall
используется, и я просто не могу обернуться вокруг его использования в таких вещах:
runST :: forall a. (forall s. ST s a) -> a
Или объяснение, почему они разные:
foo :: (forall a. a -> a) -> (Char, Bool)
bar :: forall a. ((a -> a) -> (Char, Bool))
Или целое RankNTypes
вещи...
Я склонен предпочть четкое, без жаргонского английского языка, а не виды языка, которые являются нормальными в академической среде. Большинство объяснений, которые я пытаюсь прочитать это (те, которые я могу найти через поисковые системы) иметь эти проблемы:
- Они неполны. Они объясняют одну часть использования этого ключевого слова (например, «экзистенциальные типы»), что заставляет меня чувствовать себя счастливым, пока я не прочитал код, который использует его совершенно другой способ (например,
runST
,foo
а такжеbar
над). - Они плотно упаковываются с предположениями, которые я прочитал последние в любую ветку дискретной математики, теория категории или абстрактной алгебры популярна на этой неделе. (Если я никогда не читаю слова "Проконсультируйтесь с бумагой что бы ни Для получения подробной информации о внедрении «Опять же, это будет слишком рано.)
- Они написаны таким образом, что часто превращают даже простые концепции в осторожно скрученную и сломанную грамматику и семантику.
Так...
На реальный вопрос. Может кто-нибудь полностью объяснить forall
Ключевое слово в четком, простого английского (или, если он где-то существует, укажите такое ясное объяснение, которое я пропустил), что не предполагает, что я математик, погруженный в жаргон?
Отредактировано для добавления:
Внизу более качественные ответы были два выделяемых ниже, но, к сожалению, я могу выбрать только один как лучший. ОТВЕТ НОРМАНА было подробно и полезно, объясняя вещи таким образом, что показало некоторые теоретические недостатки forall
И в то же время показывая мне некоторые практические последствия этого. Ответ Yairchu Накрыл район, никто не упомянул (переменные типа Scoped) и проиллюстрировали все концепции с кодом и сеансом GHCI. Можно было выбрать как лучшее, я бы. К сожалению, я не могу и, посмотрев на обе ответы, я решил, что Яирчу слегка краясь Нормана из-за иллюстративного кода и прилагается объяснение. Однако это немного несправедливо, потому что на самом деле мне нужна обе ответы, чтобы понять это до такой степени, что forall
Не оставляет меня слабым чувством страха, когда я вижу это в типовой подписи.
Решение
Давайте начнем с примера кода:
foob :: forall a b. (b -> b) -> b -> (a -> b) -> Maybe a -> b
foob postProcess onNothin onJust mval =
postProcess val
where
val :: b
val = maybe onNothin onJust mval
Этот код не скомпилируется (синтаксическая ошибка) на простых haskell 98. Это требует расширения для поддержки forall
ключевое слово.
В основном, есть 3 разные Обычное использование для forall
ключевое слово (или, по крайней мере, так это кажется), и у каждого есть свое собственное расширение Haskell: ScopedTypeVariables
, RankNTypes
/Rank2Types
, ExistentialQuantification
.
Код выше не получает синтаксисную ошибку с помощью любого из них, но только проверки типа с ScopedTypeVariables
включено.
Переменные типа Scoped:
Переменные типа Scoped Hype помогают одному указанию типов для кода внутри where
пункты. Это делает b
в val :: b
такой же, как b
в foob :: forall a b. (b -> b) -> b -> (a -> b) -> Maybe a -> b
.
Запутанная точка: Вы можете услышать, что когда вы опускаете forall
Из типа он на самом деле все еще неявно там. (Из ответа Нормана: «Обычно эти языки опускают форум от полиморфных типов»). Это требование правильное, но Это относится к другим применению forall
, а не к ScopedTypeVariables
использовать.
Ранг-н-типы:
Давайте начнем с этого mayb :: b -> (a -> b) -> Maybe a -> b
эквивалентно mayb :: forall a b. b -> (a -> b) -> Maybe a -> b
, Кроме когда ScopedTypeVariables
включен.
Это означает, что он работает для каждого a
а также b
.
Допустим, вы хотите сделать что-то вроде этого.
ghci> let putInList x = [x]
ghci> liftTup putInList (5, "Blah")
([5], ["Blah"])
Какой должен быть тот тип этого liftTup
? Это liftTup :: (forall x. x -> f x) -> (a, b) -> (f a, f b)
. Отказ Чтобы увидеть, почему, давайте попробуем кодировать это:
ghci> let liftTup liftFunc (a, b) = (liftFunc a, liftFunc b)
ghci> liftTup (\x -> [x]) (5, "Hello")
No instance for (Num [Char])
...
ghci> -- huh?
ghci> :t liftTup
liftTup :: (t -> t1) -> (t, t) -> (t1, t1)
«Хм .. Почему GHC выводится, что кортеж должен содержать два одного типа? Давайте скажем, они не должны быть»
-- test.hs
liftTup :: (x -> f x) -> (a, b) -> (f a, f b)
liftTup liftFunc (t, v) = (liftFunc t, liftFunc v)
ghci> :l test.hs
Couldnt match expected type 'x' against inferred type 'b'
...
Хм. так что здесь GHC не дает нам применить liftFunc
на v
потому что v :: b
а также liftFunc
хочет Ан x
. Отказ Мы действительно хотим, чтобы наша функция получила функцию, которая принимает все возможное x
!
{-# LANGUAGE RankNTypes #-}
liftTup :: (forall x. x -> f x) -> (a, b) -> (f a, f b)
liftTup liftFunc (t, v) = (liftFunc t, liftFunc v)
Так что это не liftTup
это работает для всех x
, это функция, которую она получает.
Экзистенциальное количество:
Давайте будем использовать пример:
-- test.hs
{-# LANGUAGE ExistentialQuantification #-}
data EQList = forall a. EQList [a]
eqListLen :: EQList -> Int
eqListLen (EQList x) = length x
ghci> :l test.hs
ghci> eqListLen $ EQList ["Hello", "World"]
2
Как это отличается от ранга-н-типов?
ghci> :set -XRankNTypes
ghci> length (["Hello", "World"] :: forall a. [a])
Couldnt match expected type 'a' against inferred type '[Char]'
...
С рангом-н-типовыми, forall a
означало, что ваше выражение должно соответствовать все возможно a
с. Например:
ghci> length ([] :: forall a. [a])
0
Пустой список работает как список любого типа.
Так с экзистенциально-количественной оценкой, forall
с data
Определения означают, что содержатся значение могу быть одним из Любые Подходящий тип, не то, что это должен быть одним из все Подходящие типы.
Другие советы
Может кто-нибудь полностью Объясните ключевое слово Forall в чистом виде, простого английского?
Нет. (Ну, может быть, Дон Стюарт может.)
Вот барьеры для простого, ясного объяснения или forall
:
Это квантификатор. У вас есть хотя бы небольшая логика (предикатный исчислений), чтобы увидеть универсальный или экзистенциальный квант. Если вы никогда не видели исчисления предикатов или не чувствуют себя комфортно с квантами (и я видел студентов во время квалификационных экзаменов PHD, которые не удобны), то для вас нет простого объяснения
forall
.Это тип квантификатор. Если вы не видели Система F. и получил некоторую практику, написав полиморфные типы, вы собираетесь найти
forall
запутанно. Опыт работы с Haskell или ML недостаточно, потому что обычно эти языки опускаютforall
от полиморфных типов. (На мой взгляд, это ошибка дизайна языка.)В Haskell в частности,
forall
используется в том, что я нахожу путание. (Я не теоретик типа, но моя работа приносит меня в контакт с много теории типа, и мне очень удобно.) Для меня основным источником путаницы является то, чтоforall
используется для кодирования типа, который я сам предпочел бы написать сexists
. Отказ Это оправдано хитрым типом изоморфизма, связанного с квантователями и стрелами, и каждый раз, когда я хочу понять это, я должен выглядеть и разыскивать и изоморфизм.Если вам не комфортно с идеей типа изоморфизма, или если у вас нет практики, думая о типах изоморфизмах, это использование
forall
собирается в Stymie тебя.В то время как общее понятие
forall
всегда одинаково (привязка для введения переменной типа), детали различного использования могут значительно варьироваться. Неформальный английский не очень хороший инструмент для объяснения вариаций. Чтобы действительно понять, что происходит, вам нужна математика. В этом случае соответствующая математика можно найти в вступительном тексте Бенджамина Пирса Типы и языки программирования, что это очень хорошая книга.
Что касается ваших конкретных примеров,
runST
должен сделать голову больно. Типы более высокого ранга (народное слева от стрелки) редко встречаются в дикой природе. Я призываю вас прочитать документ, которая ввелаrunST
: «Ленивые функциональные государственные нити». Отказ Это действительно хороший документ, и это даст вам гораздо лучшую интуицию для типаrunST
в частности и для типов более высокого ранга в целом. Объяснение возьмет на несколько страниц, это очень хорошо сделано, и я не собираюсь пытаться конденсироваться здесь.Рассмотреть возможность
foo :: (forall a. a -> a) -> (Char,Bool) bar :: forall a. ((a -> a) -> (Char, Bool))
Если я позвоню
bar
, Я могу просто выбрать любой типa
что мне нравится, и я могу пройти его функцию от типаa
печататьa
. Отказ Например, я могу пройти функцию(+1)
или функцияreverse
. Отказ Вы можете думать оforall
Как говорил: «Я собираюсь выбрать тип сейчас». (Техническое слово для получения типа усмотрен.)Ограничения на звонок
foo
гораздо более строгим: аргументfoo
должен быть полиморфной функцией. С таким типом, единственные функции, которые я могу передатьfoo
являютсяid
или функция, которая всегда расходится или ошибка, какundefined
. Отказ Причина в том, что сfoo
, тоforall
слева от стрелки, так как вызывающий абонентfoo
Я не хочу выбрать то, чтоa
это - скорее это реализация изfoo
это получает, чтобы выбрать то, чтоa
является. Потому чтоforall
слева от стрелки, а не над стрелкой, как вbar
, Эмейство происходит в теле функции, а не на площадке вызова.
Резюме: А. полный Объяснение forall
Ключевое слово требует математики и может быть понято только кем-то, кто изучил математику. Даже частичные объяснения трудно понять без математики. Но, возможно, мои частичные, не математические объяснения помогают немного. Иди прочитайте Lackbury и Peyton Jones на runST
!
Дополнение: Жаргон "выше", "ниже", "слева от". Они не имеют ничего общего с текстовый Способы типы написаны и все связано с абстрактными синтаксическими деревьями. В абстрактном синтаксисе, forall
Занимает имя переменной типа, а затем есть полный тип «ниже» на форуме. Стрелка принимает два типа (аргумент и тип результата) и образует новый тип (тип функции). Тип аргумента «слева от» стрелки; Это левый ребенок стрелы в абстрактном синтаксическом дереве.
Примеры:
В
forall a . [a] -> [a]
, Наконец находится над стрелкой; Что слева от стрелки[a]
.В
forall n f e x . (forall e x . n e x -> f -> Fact x f) -> Block n e x -> f -> Fact x f
Тип в скобках будет называться «Форум слева от стрелки». (Я использую такие типы в оптимизаторе, над которым я работаю.)
Мой оригинальный ответ:
Может кто-нибудь полностью объяснить ключевое слово Forall в четком, простой английском
Как указывает Норман, очень трудно дать четкое, простое английское объяснение технического термина от теории типа. Мы все пытаемся, хотя.
Есть только одно, что нужно помнить о «Forall»: Это связывает типы к некоторому объему. Отказ Как только вы понимаете это, все довольно легко. Это эквивалент «лямбда» (или форма «пусть») на уровне типа - Norman Ramsey использует понятие «левый» / «выше», чтобы передать эту же концепцию объема в его отличный ответ.
Большинство применений «Forall» очень просты, и вы можете найти их введенным в Руководство пользователя GHC, S7.8., особенно Отличный S7.8.5. на вложенные формы «народа».
В Haskell мы обычно выходим из связующего для типов, когда тип универсально Quantified, вроде так:
length :: forall a. [a] -> Int
эквивалентно:
length :: [a] -> Int
Вот и все.
Поскольку вы можете привязать переменные типа сейчас к некоторому объему, вы можете иметь принципы, отличные от верхнего уровня (»Универно определено количественно«), Как и ваш первый пример, где переменная типа видна только в структуре данных. Это позволяет для скрытых типов («экзистенциальные типы"). Или мы можем иметь произвольное гнездо привязки («звания N типов»).
Чтобы глубоко понимать системы типа, вам нужно будет выучить жаргон. Это характер информатики. Тем не менее, простое использование, как указано выше, должна быть в состоянии быть схвачена интуитивно, по аналогии с «данной» на уровне значения. Отличное введение Lackbury и Peyton Jones.
Они плотно упаковываются с предположениями, которые я прочитал последние в любую ветку дискретной математики, теория категории или абстрактной алгебры популярна на этой неделе. (Если я никогда не читаю слова «Проконсультируйтесь с бумагой, что бы ни за подробности реализации» снова, это будет слишком рано.)
Эр, а как насчет простого логики первого порядка? forall
довольно четко относится к Универсальное определение количества, и в этом контексте термин экзистенциально имеет больше смысла, хотя это было бы менее неловко, если бы было exists
ключевое слово. Будет ли количественная оценка эффективно универсальной или экзистенциальной, зависит от размещения квантификатора относительно того места, где используются переменные, на которых используются переменные, на которой стрелка функции, и это все немного запутано.
Итак, если это не поможет, или если вы просто не любите символическую логику, с более функциональной перспективы программирования - ISH вы можете подумать о переменных типах как просто быть (неявным) тип Параметры к функции. Функции Принимая параметры типа в этом смысле традиционно написаны с использованием Capital Lambda по какой-либо причине, которую я напишу здесь как /\
.
Итак, рассмотрим id
Функция:
id :: forall a. a -> a
id x = x
Мы можем переписать его как лямбдас, перемещение параметра типа «тип типа» из подписи типа и добавление аннотаций встроенного типа:
id = /\a -> (\x -> x) :: a -> a
Вот одно и то же сделано для const
:
const = /\a b -> (\x y -> x) :: a -> b -> a
Так что ваши bar
Функция может быть что-то вроде этого:
bar = /\a -> (\f -> ('t', True)) :: (a -> a) -> (Char, Bool)
Обратите внимание, что тип функции, данной bar
Как аргумент зависит от bar
параметр типа. Подумайте, что если у вас было что-то вроде этого:
bar2 = /\a -> (\f -> (f 't', True)) :: (a -> a) -> (Char, Bool)
Здесь bar2
применяет функцию к чему-то типу Char
, так дарить bar2
любой тип параметра, отличный от Char
приведет к ошибке типа.
С другой стороны, вот что foo
может выглядеть как:
foo = (\f -> (f Char 't', f Bool True))
В отличие от bar
, foo
На самом деле на самом деле не принимает какие-либо параметры типа! Требуется функция, которая сам принимает тип параметра, затем применяется, что функция до двух разные Типы.
Так, когда вы видите forall
в типовой подписи, просто подумайте об этом как о лямбда выражение для типовых подписей. Отказ Просто как обычный лямбдас, объем forall
Расширется как можно дальше вправо, до того, чтобы приложить скобки, а также как переменные, связанные в обычной лямбде, переменные типа, связанные forall
только в объеме в пределах количественного выражения.
Пост скриптум: Возможно, вы можете задаться вопросом - теперь, когда мы думаем о функциях, принимающих параметры типа, почему мы не можем сделать что-то более интересное с этими параметрами, чем поместить их в подпись типа? Ответ в том, что мы можем!
Функция, которая помещает переменные типа вместе с этикеткой и возвращает новый тип Тип конструктор, который вы могли бы написать что-то вроде этого:
Either = /\a b -> ...
Но нам понадобится совершенно новая нотация, потому что такой тип написан, как Either a b
, уже наводит на виду «применять функцию Either
к этим параметрам ».
С другой стороны, функция, которая вроде «шаблон шаблона» на параметрах его типа, возвращает разные значения для разных типов, является Метод класса типа. Отказ Небольшое расширение моему /\
Синтаксис выше предполагает что-то вроде этого:
fmap = /\ f a b -> case f of
Maybe -> (\g x -> case x of
Just y -> Just b g y
Nothing -> Nothing b) :: (a -> b) -> Maybe a -> Maybe b
[] -> (\g x -> case x of
(y:ys) -> g y : fmap [] a b g ys
[] -> [] b) :: (a -> b) -> [a] -> [b]
Лично я думаю, что я предпочитаю фактический синтаксис Haskell ...
Функция, которую «шаблон соответствует» параметрам его типа и возвращает произвольную, существующий тип является Тип семьи или Функциональная зависимость- В прежнем случае он даже уже выглядит отлично, как определение функции.
Вот быстрое и грязное объяснение в обычных условиях, с которыми вы, вероятно, уже знакомы.
То forall
Ключевое слово действительно используется только одним способом Haskell. Это всегда означает то же самое, когда вы видите это.
Универсальное определение количества
А. Универновально количественный тип это тип формы forall a. f a
. Отказ Значение этого типа можно рассматривать как функция это принимает А. тип a
как его аргумент и возвращает стоимость Тип f a
. Отказ За исключением того, что в Haskell эти аргументы типа передаются неявно системой типа. Эта «функция» должна дать вам то же значение, независимо от того, какой тип он получает, поэтому значение полиморфный.
Например, рассмотрим тип forall a. [a]
. Отказ Значение этого типа принимает другой тип a
и дает обратно список элементов этого же типа a
. Отказ Конечно, есть только одна возможная реализация. Это придется дать вам пустой список, потому что a
может быть абсолютно любой тип. Пустой список - это единственное значение списка, которое является полиморфным в своем типе элемента (так как у него нет элементов).
Или тип forall a. a -> a
. Отказ Вызывающий такая функция обеспечивает как тип a
и значение типа a
. Отказ Затем реализация должна вернуть значение того же типа a
. Отказ Есть только одна возможная реализация снова. Это придется вернуть то же значение, которое оно было дано.
Экзистенциальное количество
Ан экзистенциально количественный тип будет иметь форму exists a. f a
, если Haskell поддержал это обозначение. Значение этого типа можно рассматривать как пара (или «продукт»), состоящий из типа a
и значение типа f a
.
Например, если у вас есть значение типа exists a. [a]
, У вас есть список элементов некоторых типов. Это может быть любым типом, но даже если вы не знаете, каково это, есть много, вы можете сделать с таким списком. Вы можете изменить его изменить, или вы можете подсчитать количество элементов или выполнять любые другие операции списка, которая не зависит от типа элементов.
Хорошо, так подождите минуту. Почему использование Haskell forall
Чтобы обозначить «экзистенциальный» тип, как следующее?
data ShowBox = forall s. Show s => SB s
Это может быть запутано, но это действительно описывает Тип конструктора данных SB
:
SB :: forall s. Show s => s -> ShowBox
После построенного, вы можете думать о значении типа ShowBox
состоящий из двух вещей. Это тип s
вместе со значением типа s
. Отказ Другими словами, это значение экзистенциально количественного типа. ShowBox
может быть действительно написан как exists s. Show s => s
, если Haskell поддержал это обозначение.
runST
и друзья
Учитывая, как эти люди?
foo :: (forall a. a -> a) -> (Char,Bool)
bar :: forall a. ((a -> a) -> (Char, Bool))
Давайте сначала возьми bar
. Отказ Требуется тип a
и функция типа a -> a
, и производит ценность типа (Char, Bool)
. Отказ Мы могли бы выбрать Int
как то a
и дать ему функцию типа Int -> Int
Например. Но foo
отличается. Это требует, чтобы реализация foo
Уметь пройти любой тип, который он хочет, чтобы функцию, которую мы даем. Поэтому единственная функция, которую мы могли бы разумно дать, это id
.
Теперь мы должны быть в состоянии решить значение типа runST
:
runST :: forall a. (forall s. ST s a) -> a
Так runST
должен быть в состоянии произвести значение типа a
, независимо от того, какой тип мы даем как a
. Отказ Для этого ему нужен аргумент типа forall s. ST s a
которые под капотом просто функция типа forall s. s -> (a, s)
. Отказ Эта функция должна иметь возможность производить значение типа (a, s)
Независимо от того, какой тип реализации runST
решает дать как s
.
Хорошо, так что? Преимущество заключается в том, что это ставит ограничение на абонент runST
в этом типе a
не может включать тип s
вообще. Вы не можете пройти его значение типа ST s [s]
, Например. Что это значит на практике, состоит в том, что реализация runST
свободно выполнять мутацию со значением типа s
. Отказ Система типа гарантирует, что эта мутация является местной для реализации runST
.
Тип runST
является примером Полиморфный тип ранга-2 потому что тип его аргумента содержит forall
квантификатор. Тип foo
выше также ранг 2. Обычный полиморфный тип, как и bar
, это ранг-1, но он становится ранга-2, если виды аргументов должны быть полиморфными, с их собственными forall
квантификатор. И если функция принимает аргументы RANK-2, то его тип ранга 3 и так далее. В общем, тип, который принимает полиморфные аргументы ранга n
имеет ранг n + 1
.
Причина, по которой имеется разное использование этого ключевого слова, заключается в том, что он фактически используется как минимум в двух разных расширениях типа системы: типы более высокого ранга и экзистенны.
Вероятно, лучше всего читать и понимать эти две вещи отдельно, а не пытаться получить объяснение того, почему «Forall» является подходящим битом синтаксиса в одном и том же времени.
Может кто-нибудь полностью объяснить ключевое слово Forall в четком, простого английского (или, если он где-то существует, указать на такое ясное объяснение, которое я пропустил), что не предполагает, что я математик, погруженный в жаргон?
Я собираюсь попытаться объяснить только значение и, возможно, применение forall
В контексте систем Haskell и его типа.
Но прежде чем вы поймете, что я хотел бы направить вас к очень доступному и приятному разговору под названием Runar BjarnasonОграничения освобождают, свободы ограничивают«. Разговор полон примеров из реальных случаев использования, а также примеры в Scala для поддержки этого утверждения, хотя он не упоминает forall
. Отказ Я постараюсь объяснить forall
Перспектива ниже.
CONSTRAINTS LIBERATE, LIBERTIES CONSTRAIN
Это очень важно для переваривания и верить в это утверждение, чтобы продолжить следующее объяснение, поэтому я призываю вас посмотреть разговор (хотя бы его части).
Теперь очень распространенный пример, показывающий выразительность системы Haskell Type, является эта подпись типа:
foo :: a -> a
Говорят, что дано эта подпись типа, есть только одна функция, которая может удовлетворить этот тип, и это identity
функция или что более широко известно id
.
На начальных этапах меня изучают Haskell, мне всегда интересуются функции ниже:
foo 5 = 6
foo True = False
они оба удовлетворяют подписанию вышеприведенной типовой подписи, а затем зачем народные люди Haskell утверждают, что это id
Один, который удовлетворяет типу подписи?
Это потому, что есть неявный forall
скрыто в типовой подписи. Фактический тип:
id :: forall a. a -> a
Итак, теперь давайте вернемся к заявлению: Ограничения освобождают, свободы ограничивают
Перевод, что в систему типа это утверждение становится:
Ограничение на уровне типа, становится свободой на термическом уровне
а также
Свобода на уровне типа становится ограничением на уровне термина
Давайте попробуем доказать первое утверждение:
Ограничение на уровне типа ..
Так что положить ограничение на нашу тип подписи
foo :: (Num a) => a -> a
становится свободой на термическом уровнедает нам свободу или гибкость для написания всех этих
foo 5 = 6
foo 4 = 2
foo 7 = 9
...
То же самое можно наблюдать, сдерживая a
с любым другим типом и т. Д.
Так что теперь, что эта подпись типа: foo :: (Num a) => a -> a
Переводится на это:
∃a , st a -> a, ∀a ∈ Num
Это известно как экзистенциальное количество, которое переводит на Существует некоторые экземпляры a
для которой функция при кормлении чего-то типа a
Возвращает что-то в одном типе, и эти случаи все принадлежат к набору чисел.
Следовательно, мы можем видеть добавление ограничений (что a
Должно быть принадлежать к множеству номеров), освобождает термин уровень, чтобы иметь несколько возможных реализаций.
Теперь приезжают на второе утверждение и тот, который на самом деле несет объяснение forall
:
Свобода на уровне типа становится ограничением на уровне термина
Так что теперь давайте освободим функцию на уровне типа:
foo :: forall a. a -> a
Теперь это переводит на:
∀a , a -> a
что означает, что реализация эта подпись типа должна быть такова, что она a -> a
для всех обстоятельств.
Так что теперь это начинает ограничивать нас на термине уровне. Мы больше не можем писать
foo 5 = 7
потому что эта реализация не удовлетворяла, если мы поставим a
как Bool
. a
может быть А. Char
или а [Char]
или пользовательский тип данных. При любых обстоятельствах он должен вернуть что-то из подобного типа. Эта свобода на уровне типа - это то, что известно как универсальное количество количественной оценки и единственная функция, которая может удовлетворить это
foo a = a
который обычно известен как identity
функция
Следовательно forall
это liberty
на уровне типа, реальная цель которого является constrain
термин уровень к конкретной реализации.
Как экзистенциально существует?
С экзистенциально определенным количественным
forall
сdata
Определения означают, что содержатся значение могу быть одним из Любые Подходящий тип, не то, что это должен быть одним из все Подходящие типы. - Ответ Ячиру
Объяснение почему forall
в data
Определения изоморфны для (exists a. a)
(pseudo-haskell) можно найти в Викибукс "Haskell / экзистенциально количественные типы".
Ниже приведен краткий представитель Verbatim:
data T = forall a. MkT a -- an existential datatype
MkT :: forall a. a -> T -- the type of the existential constructor
Когда образец - сопоставление / деконструкция MkT x
, что такое тип x
?
foo (MkT x) = ... -- -- what is the type of x?
x
может быть любой тип (как указано в forall
), и поэтому это тип:
x :: exists a. a -- (pseudo-Haskell)
Следовательно, следующие являются изоморфными:
data T = forall a. MkT a -- an existential datatype
data T = MkT (exists a. a) -- (pseudo-Haskell)
Forall означает накормить
Моя простая интерпретация всего этого, в том, что "forall
Действительно означает «для всех». Важное различие, чтобы сделать это влияние forall
на определение против функции заявление.
А. forall
означает то определение Значения или функции должны быть полиморфными.
Если вещь определена, является полиморфной стоимость, тогда это означает, что значение должно быть действительным для всех подходящих a
, что вполне ограничительно.
Если вещь определена, является полиморфной функция, Тогда это означает, что функция должна быть действительной для всех подходящих a
, который не является этим ограничительным, потому что только потому, что функция является полиморфной, не означает, что параметр применяемый должны быть полиморфными. То есть, если функция действительна для всех a
, Тогда наоборот Любые подходящее a
возможно применяемый к функции. Однако тип параметра может быть выбран только один раз в определении функции.
Если forall
находится внутри типа функции параметра (т. Е. Rank2Type
) тогда это значит применяемый Параметр должен быть действительно полиморфный, чтобы соответствовать идее forall
означает определение является полиморфным. В этом случае тип параметра может быть выбран более одного раза в определении функции («И выбран реализацией функции», как указано норман)
Поэтому причина, по которой экзистенциальны data
Определения позволяет Любые a
это потому, что конструктор данных является полиморфной функция:
MkT :: forall a. a -> T
Вид МКТ :: a -> *
Что означает любое a
может быть применен к функции. В отличие от, скажем, полиморфный стоимость:
valueT :: forall a. [a]
Вид валюты :: a
Что означает, что определение Valuet должен быть полиморфным. В этом случае, valueT
можно определить как пустой список []
всех типов.
[] :: [t]
Различия
Хотя значение для forall
соответствует ExistentialQuantification
а также RankNType
, Экзистенны имеют разницу с data
Конструктор может быть использован в сопоставлении шаблона. Как документировано в Руководство пользователя GHC:
Когда сопоставление шаблона каждый шаблон соответствует новой, отличному типу для каждой переменной экзистенциальной тип. Эти типы не могут быть объединены с любым другим типом, и они не могут уйти от объема матча шаблона.