Существуют ли "комбинаторы уровня типа"? Будут ли они существовать в будущем?
Многое из того, что делает haskell действительно хорошим для использования, на мой взгляд, это комбинаторы, такие как (.)
, flip
, $
<*>
и т. д. Такое ощущение, что я могу создать новый синтаксис, когда мне это нужно.
Некоторое время назад я делал что-то, что было бы чрезвычайно удобно, если бы я мог "перевернуть" конструктор типов. Предположим, у меня есть конструктор типов:
m :: * -> * -> *
и что у меня есть класс MyClass
который нуждается в типе с конструктором типа с видом * -> *
, Естественно, я бы выбрал кодирование типа таким образом, чтобы я мог сделать:
instance MyClass (m a)
Но предположим, что я не могу изменить этот код, и предположим, что то, что действительно вписывается в MyClass
это что-то вроде
type w b = m b a
instance MyClass w where
...
и тогда мне придется активировать XTypeSynonymInstances
, Есть ли способ создать "комбинатор уровня типа" Flip
такой, что я могу просто сделать:
instance MyClass (Flip m a) where
...
?? Или другие обобщения типа общих операторов, которые мы используем в haskell? Это даже полезно или я просто болтаю?
Редактировать:
Я мог бы сделать что-то вроде:
newtype Flip m a b = Flip (m b a)
newtype Dot m w a = Dot m (w a)
...
Но тогда я должен был бы использовать конструкторы данных Flip
, Dot
,... вокруг для сопоставления с образцом и т. д. Стоит ли это?
3 ответа
Ваш вопрос имеет смысл, но ответ таков: нет, в настоящее время это невозможно.
Проблема в том, что (в системе типов GHC Haskell) вы не можете иметь лямбды на уровне типов. Если вы попробуете что-то похожее на эмуляцию лямбды на уровне типов, вы обнаружите, что она не работает. (Я знаю, потому что я сделал.)
Что вы можете сделать, это объявить свои новые типы Flip, а затем написать экземпляры классов, которые вы хотите для них, мучительно с обертыванием и развертыванием (кстати: используйте синтаксис записи), и тогда клиенты классов могут использовать новые типы в Тип подписей и не нужно беспокоиться о деталях.
Я не теоретик типов, и я не знаю деталей, почему именно у нас не может быть лямбд на уровне типов. Я думаю, что это как-то связано с тем, что вывод типов становится невозможным, но опять же, я не знаю.
Вы можете сделать следующее, но я не думаю, что это на самом деле очень полезно, так как вы все еще не можете применить его частично:
{-# LANGUAGE TypeFamilies, FlexibleInstances #-}
module Main where
class TFlip a where
type FlipT a
instance TFlip (f a b) where
type FlipT (f a b) = f b a
-- *Main> :t (undefined :: FlipT (Either String Int))
-- (undefined :: FlipT (Either String Int)) :: Either Int [Char]
Также посмотрите это предыдущее обсуждение: лямбда для выражений типов в Haskell?
Я пишу здесь ответ только для того, чтобы прояснить ситуацию и рассказать о достижениях за последние годы. В Haskell имеется множество функций, и теперь вы можете написать несколько операторов по типу. С помощью $
Вы можете написать что-то вроде этого:
foo :: Int -> Either String $ Maybe $ Maybe Int
избегать скобок вместо старого доброго
foo :: Int -> Either String (Maybe (Maybe Int))