Lambda для выражений типа в Haskell?
Имеет ли Haskell или конкретный компилятор что-нибудь вроде лямбда типа (если это даже термин)?
Чтобы уточнить, скажем, у меня параметризованный тип Foo a b
и хочу, чтобы Foo _ b
был экземпляром, скажем, Functor. Есть ли какой-нибудь механизм, который позволил бы мне сделать что-то похожее на
instance Functor (\a -> Foo a b) where
...
?
Ответы
Ответ 1
Из TypeCompose:
newtype Flip (~>) b a = Flip { unFlip :: a ~> b }
http://hackage.haskell.org/packages/archive/TypeCompose/0.6.3/doc/html/Control-Compose.html#t:Flip
Кроме того, если что-то есть Functor в двух аргументах, вы можете сделать его бифунтером:
http://hackage.haskell.org/packages/archive/category-extras/0.44.4/doc/html/Control-Bifunctor.html
(или в более поздней версии категории - более общая версия: http://hackage.haskell.org/packages/archive/category-extras/0.53.5/doc/html/Control-Functor.html#t:Bifunctor)
Ответ 2
В то время как sclv ответил на ваш прямой вопрос, я добавлю в сторону, что существует более чем одно возможное значение для "лямбда-типа уровня". Haskell имеет множество операторов типа, но ни один из них не ведет себя как надлежащие лямбды:
- Конструкторы типов: Операторы абстрактного типа, которые вводят новые типы. Учитывая тип
A
и конструктор типа F
, приложение-приложение F A
также является типом, но не содержит дополнительной информации (типа уровня), чем "это F
применяется к A
".
- Полиморфные типы: Тип типа
a -> b -> a
неявно означает forall a b. a -> b -> a
. forall
связывает переменные типа в своей области действия, таким образом, ведет себя как lambda. Если память служит мне, это примерно "столичная лямбда" в System F.
- Синонимы типов: Ограниченная форма операторов типов, которые должны быть полностью применены, и могут создавать только базовые типы и конструкторы типов.
- Типовые классы: По существу функции от типов/типов конструкторов до значений, с возможностью проверки аргумента типа (т.е. путем сопоставления шаблонов в конструкторах типа примерно так же, как с шаблоном регулярных функций на конструкторах данных) и служит для определения предиката принадлежности для типов. Они по большей части более похожи на регулярную функцию, но очень ограничены: типы классов не являются первоклассными объектами, которые можно манипулировать, и они работают с типами только как входные (не выводятся), а значения только в качестве вывода (определенно не вход).
- Функциональные зависимости: Наряду с некоторыми другими расширениями, они позволяют типам классов неявно создавать типы в качестве результатов, которые затем могут использоваться в качестве параметров для других классов классов. Все еще очень ограниченный, например. не имея возможности использовать другие типы классов в качестве аргументов.
- Типы семейств: Альтернативный подход к тем, какие функциональные зависимости выполняются; они позволяют определять функции по типам, которые выглядят намного ближе к регулярным функциям уровня ценности. Однако обычные ограничения все же применяются.
Другие расширения ослабляют некоторые из упомянутых ограничений или предоставляют частичные обходные пути (см. также хакерство типа Oleg). Тем не менее, в значительной степени одна вещь, которую вы не можете сделать нигде, - это именно то, о чем вы просили, а именно ввести новую область привязки с анонимной абстракцией функции.
Ответ 3
Мне не нравится идея ответить на мой собственный вопрос, но, по-видимому, по словам нескольких людей в #haskell на Freenode, у Haskell нет ямбдов на уровне уровня.
Ответ 4
EHC (и, возможно, также его преемник, UHC) имеет lambdas на уровне типа, но они недокументированы и не так сильны, как на языке с зависимым от языка. Я рекомендую использовать язык с надписью, такой как Agda (аналогичный Haskell) или Coq (другой, но по-прежнему чистый функционал по своему ядру, и его можно интерпретировать и компилировать либо лениво, либо строго!) Но я склонен к таким языкам, и это, вероятно, 100x overkill за то, что вы просите здесь!
Ответ 5
Ближайшим, которого я знаю, чтобы получить тип лямбда, является определение синонима типа. В вашем примере
data Foo a b = Foo a b
type FooR a b = Foo b a
instance Functor (FooR Int) where
...
Но даже с -XTypeSynonymInstances -XFlexibleInstances это не работает; GHC ожидает, что тип syn будет полностью применен в голове экземпляра. Может быть какой-то способ организовать его с семействами типов.
Ответ 6
Да, что сказал Гейб, на который несколько отвечают семейства типов:
http://www.haskell.org/haskellwiki/GHC/Type_families
Ответ 7
В зависимости от ситуации вы можете заменить исходное определение типа "перевернутой" версией, а затем сделать синоним типа для "правильной" версии.
От
data X a b = Y a b
instance Functor (\a -> X a b) where ...
в
data XFlip b a = Y a b -- Use me for instance decalarations
type X a b = XFlip b a -- Use me for everything else
instance Functor XFlip where ...