Вопрос

Я начинаю понимать, как 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 вещи...

Я склонен предпочть четкое, без жаргонского английского языка, а не виды языка, которые являются нормальными в академической среде. Большинство объяснений, которые я пытаюсь прочитать это (те, которые я могу найти через поисковые системы) иметь эти проблемы:

  1. Они неполны. Они объясняют одну часть использования этого ключевого слова (например, «экзистенциальные типы»), что заставляет меня чувствовать себя счастливым, пока я не прочитал код, который использует его совершенно другой способ (например, runST, foo а также bar над).
  2. Они плотно упаковываются с предположениями, которые я прочитал последние в любую ветку дискретной математики, теория категории или абстрактной алгебры популярна на этой неделе. (Если я никогда не читаю слова "Проконсультируйтесь с бумагой что бы ни Для получения подробной информации о внедрении «Опять же, это будет слишком рано.)
  3. Они написаны таким образом, что часто превращают даже простые концепции в осторожно скрученную и сломанную грамматику и семантику.

Так...

На реальный вопрос. Может кто-нибудь полностью объяснить 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:

Когда сопоставление шаблона каждый шаблон соответствует новой, отличному типу для каждой переменной экзистенциальной тип. Эти типы не могут быть объединены с любым другим типом, и они не могут уйти от объема матча шаблона.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top