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

Ответ 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 ...