Определите списки с наименьшей фиксированной точкой, суммой и типами продуктов

Я хочу определить списки, используя только определения этого типа:

data Unit = Unit
data Prod a b = P a b
data Sum a b = L a | R b
newtype Mu f = Mu (forall a . (f a -> a) -> a)

Мне удалось определить натуральные числа следующим образом:

zeroMu = Mu $ \f -> f $ L Unit
succMu (Mu g) = Mu $ \f -> f $ R $ g f

Я знаю, как определять списки с помощью дополнительного типа данных:

data ListF a x = NilF | ConsF a x
nilMu' = Mu $ \f -> f $ NilF
consMu' x (Mu g) = Mu $ \f -> f $ ConsF x $ g f

«Лучшее», что я могу получить, это это, но оно не проверяет тип (предполагаемый тип - µL.(1+(a*L))):

nilMu = Mu $ \f -> f $ L Unit
consMu x (Mu g) = Mu $ \f -> f $ R $ P x $ g f

Как я могу определить nilMu и consMu, используя только ранее определенные типы и их конструкторы?

Изменить

Как объясняет ответ @chi, это можно сделать, определив newtype следующим образом:

newtype F a x = F (Sum Unit (Prod a x))
nilMu = Mu $ \f -> f $ F $ L Unit
consMu x (Mu g) = Mu $ \f -> f $ F $ R $ P x $ g f

Он проверяет тип, но требует определения нового типа.

Цель этого вопроса состоит в том, чтобы расширить просто типизированную комбинаторную логику единицей, продуктом, суммой и рекурсивными типами. Первые три типа легко реализовать с помощью 7 новых комбинаторов (unit, pair, first, second, left, right, case). Рекурсивные типы также кажутся простыми в реализации, просто добавьте комбинатор конструктора типов mu, но, как показывает этот вопрос, он недостаточно гибок без дополнительных языковых конструкций.

Есть ли решение этой проблемы? Есть ли комбинаторная логика с рекурсивными типами для консультаций?


person user3368561    schedule 18.06.2018    source источник
comment
Кросс-опубликовано: stackoverflow.com/q/50911735/781723, cs.stackexchange.com/q/93207/755. Пожалуйста, не публикуйте один и тот же вопрос на нескольких сайтах. Каждое сообщество должно иметь честный шанс ответить без чьей-либо траты времени.   -  person D.W.    schedule 18.06.2018
comment
Вы можете попробовать определить комбинаторы SKI на уровне типа, что позволит вам выразить уровень типа функция без специального нового типа. С ним весело играть, но он становится очень грязным.   -  person luqui    schedule 19.06.2018
comment
@luqui Но если вы можете это сделать, это означает, что проверка типов неразрешима. Моя цель, ограничивающая себя такой слабой теорией типов, состоит в том, чтобы получить полностью выведенные типы, поэтому мне не нужно добавлять ни определения типов, ни объявления, а программы представляют собой простые строки составленных комбинаторов без объявлений типов и сигнатур.   -  person user3368561    schedule 19.06.2018


Ответы (1)


Вы не можете сделать это без дополнительных data или newtype в Haskell.

Для этого нужно было бы написать

nilMu :: Mu (\l -> S (P a l) ())
consMu :: a -> Mu (\l -> S (P a l) ()) -> Mu (\l -> S (P a l) ())

но Haskell не позволяет использовать функции уровня типа таким образом. Mu можно применять только к конструктору типа типа * -> *, а не к функции уровня типа того же типа.

nilMu :: Mu (F a)
consMu :: a -> Mu (F a) -> Mu (F a)

где F a определяется как дополнительный тип

newtype F a x = F (S (P a x) ())

По той причине, по которой Haskell не поддерживает функции уровня типа, рассмотрите

assuming foo :: f a -> f Char
infer    foo True :: ???

Можно возразить, что в foo True True есть Bool, поэтому мы можем вывести f = \t->t и a = Bool. Результат foo True :: (\t->t) Char = Char.

Можно также возразить, что мы можем вывести f = \t->Bool и a = String и что в результате получится foo True :: (\t->Bool) Char = Bool.

В общем, нам это не нравится. Мы хотим, чтобы вывод типа происходил путем сопоставления шаблонов f и a с фактическим типом. Для этого мы хотим, чтобы и f, и a имели соответствующее "очевидное" имя в фактическом типе.

Что бы это ни стоило, вы можете сделать это в языках с зависимым типом, таких как Coq, Agda, Idris и т. д. Там вывод типов не будет работать для кода, подобного foo True выше, поскольку f не может быть предполагаемый. Хуже того, в этих языках, если bar :: f a -> ... и мы называем bar [True], то f нельзя вывести из [], потому что это не единственное решение (однако у них есть хорошие эвристики, которые часто работают в любом случае, даже если общая проблема неразрешима). ).

person chi    schedule 18.06.2018
comment
Являются ли функции уровня типа единственным способом? Они являются излишним для того, что я пытаюсь сделать. - person user3368561; 18.06.2018
comment
@ user3368561 В ответе говорится, что вы не можете использовать функции уровня типа. Что ты хочешь этим сказать? - person AJF; 18.06.2018
comment
@AJFarmar Не в (текущем) Haskell, да, но мой вопрос более общий и не связан с ним строго. У меня нет проблем с теоретическими ответами. - person user3368561; 18.06.2018
comment
@user3368561 user3368561 Ну, как бы вы набрали nilMu :: Mu ?? без функции уровня типа? - person chi; 18.06.2018
comment
Другая точка зрения на то, почему Haskell не допускает функции уровня типа (и, следовательно, также не допускает частично применяемые синонимы типов), заключается в том, что полиморфизм более высокого типа требует для решения унификации более высокого порядка, что в общем случае неразрешимо; как бы то ни было, учитывая a x ~ b y, компилятор всегда может вывести a ~ b и x ~ y, что очень удобно как для рассуждений программиста, так и для производительности компилятора. - person Jon Purdy; 18.06.2018