7

Можно кодировать различные типы в нетипизированном лямбда-исчислении с помощью функций более высокого порядка.Внедрение более высоких типов типов (монады!) В нетипизированное лямбда-исчисление

Examples: 
zero = λfx.  x 
one = λfx.  fx 
two = λfx. f(fx) 
three = λfx. f(f(fx)) 
etc 

true = λtf. t 
false = λtf. f 

tuple = λxyb. b x y 
null = λp. p (λxy. false) 

Мне было интересно, если какое-либо исследование ушло на внедрение других менее традиционных типов. Было бы замечательно, если бы была какая-то теорема, утверждающая, что любой тип может быть встроен. Возможно, существуют ограничения, например, могут быть встроены только типы рода *.

Если действительно возможно представить менее традиционные типы, было бы замечательно увидеть пример. Мне особенно нравится видеть, как выглядят члены класса типа монады.

ответ

12

Вы смешиваете уровень уровня с уровнем значения. В нетипизированном лямбда-исчислении нет монад. Модифицированные операции (уровень ценности) могут выполняться, но не монады (тип уровня). Однако сами операции могут быть одинаковыми, поэтому вы не теряете выразительной силы. Поэтому сам вопрос не имеет смысла.

+0

Так как лямбда-исчисления Тьюринга можно кодировать любой вычислительный процесс в нем. Я предполагаю, что речь идет именно о кодировании. Конечно, нетипизированное исчисление не имеет в нем типов, но можно кодировать некоторые объекты, которые ведут себя как типы и механизмы ввода. Точно так же, как у него нет bools и numbers, но есть соответствующие кодировки, указанные в вопросе. [Answer by Dan] (https://stackoverflow.com/a/8936209/707926) в большей степени соответствует этому пониманию. –

1

Ну, у нас уже есть кортежи и булевы, следовательно, мы можем представить Either и в свою очередь, любой нерекурсивную тип суммы, основанный на том, что:

type Either a b = (Bool, (a, b)) 
type Maybe a = Either() a 

А Может является членом класса типа Монады. Перевод на лямбда-нотацию оставлен как упражнение.

17

Можно представить практически любой тип, который вы хотите. Но поскольку монадические операции выполняются по-разному для каждого типа, это не можно написать >>= один раз и заставить его работать для каждого экземпляра.

Однако, вы можете написать общие функции, которые зависят от доказательств из экземпляра класса типов. Рассмотрим e здесь, чтобы быть кортежем, где fst e содержит определение «привязки», а snd e содержит определение «возврат».

bind = λe. fst e -- after applying evidence, bind looks like λmf. ___ 
return = λe. snd e -- after applying evidence, return looks like λx. ___ 

fst = λt. t true 
snd = λt. t false 

-- join x = x >>= id 
join = λex. bind e x (λz. z) 

-- liftM f m1 = do { x1 <- m1; return (f x1) } 
-- m1 >>= \x1 -> return (f x1) 
liftM = λefm. bind e m (λx. return e (f x)) 

Вам нужно было бы определить «доказательство кортежа» для каждого экземпляра Монады. Обратите внимание, что мы определили bind и return: они работают точно так же, как и другие «общие» методы Monad, которые мы определили: сначала им нужно дать доказательства Monad-ness, а затем они функционируют должным образом.

Мы можем представлять Maybe как функцию, которая принимает 2 входа, первая - это функция для выполнения, если она равна Just x, а вторая - это значение, чтобы заменить ее, если она не указана.

just = λxfz. f x 
nothing = λfz. z 

-- bind and return for maybes 
bindMaybe = λmf. m f nothing 
returnMaybe = just 

maybeMonadEvidence = tuple bindMaybe returnMaybe 

Списки аналогичны, представляют собой Список в качестве функции его сгибания. Поэтому список - это функция, которая принимает 2 входа, «минус» и «пустой». Затем он выполняет foldr myCons myEmpty в списке.

nil = λcz. z 
cons = λhtcz. c h (t c z) 

bindList = λmf. concat (map f m) 
returnList = λx. cons x nil 

listMonadEvidence = tuple bindList returnList 

-- concat = foldr (++) [] 
concat = λl. l append nil 

-- append xs ys = foldr (:) ys xs 
append = λxy. x cons y 

-- map f = foldr ((:) . f) [] 
map = λfl. l (λx. cons (f x)) nil 

Either также прост. Представляем любой тип как функцию, которая выполняет две функции: одну для применения, если она является Left, а другая для применения, если она является Right.

left = λlfg. f l 
right = λrfg. g r 

-- Left l >>= f = Left l 
-- Right r >>= f = f r 
bindEither = λmf. m left f 
returnEither = right 

eitherMonadEvidence = tuple bindEither returnEither 

Не забывайте, что функции сами(a ->) образуют монаду. И все в исчислении лямбда - это функция ... так что ... не думайте об этом слишком сильно. ;) Вдохновленный непосредственно из источника Control.Monad.Instances

-- f >>= k = \ r -> k (f r) r 
bindFunc = λfkr. k (f r) r 
-- return = const 
returnFunc = λxy. x 

funcMonadEvidence = tuple bindFunc returnFunc 
+6

NB: это в основном то, как Typeclasses реализованы в GHC. «Свидетельский кортеж» вместо этого называется «словарным знаком» (или люди C могут называть его «vtable»). –

+1

Эдвард К. сделал в основном это по схеме: https://github.com/ekmett/scheme-monads –

Смежные вопросы