Как итерировать или повторять нетипизированную функцию n раз?

Я практикуюсь с компилятором OCaml, и я выполняю небольшое задание, где мы должны реализовать числа Чёрча, определяемые как:

zz = pair c0 c0; ss = λp. pair ( snd p) ( plus c1 (snd p)); prd = λm. fst (m ss zz );

и для расчета ss я хочу реализовать плюс:

plus = λm. λn. λs. λz. m s (n s z)

поэтому мой вопрос в том, как реализовать funtion plus, например, n раз succ 0?

Я пробовал как plus = lambda m. lambda n. lambda s. lambda z. m s (n s z);, но это неправильно в компиляторе.

Я заметил, что работаю в компиляторе OCaml и пишу все свои функции в файле func.f, а не в файле .ml.

https://www.cis.upenn.edu/%7Ebcpierce/tapl/ код оттуда, папка fulluntyped


person Zethuman    schedule 17.03.2021    source источник
comment
У меня нет ответа, потому что я не очень понимаю ваш вопрос, я боюсь. Во-первых, вы работаете с языком OCaml или вы работаете с компилятором OCaml (реализацией, т.е. внутренними компонентами компилятора)? Я предполагаю, что вы работаете с языком OCaml, поскольку этим занимается Пирс. Если вы работаете с OCaml, то должны знать, что в OCaml нет ключевого слова lambda. Ваш код даже близко не соответствует правильному OCaml. Мне кажется, что главное, что вам нужно сделать дальше, это выучить достаточно OCaml, чтобы продолжить. Вы можете попробовать учебные ресурсы на ocaml.org.   -  person Jeffrey Scofield    schedule 17.03.2021
comment
@JeffreyScofield Вы правильно поняли, мне недостаточно объяснили задачу. Но я пытаюсь понять, читая книгу, но не могу реализовать в коде то, что написано в книге. То, что ключевого слова lambda нет на OCaml я знаю, оно определено в lexer.ml (его можно увидеть в ссылке, которую я присылаю) и оказывается добавляется вручную. Реализовал не или xor nand, но сейчас застрял на плюсе, так как не представляю как перебирать и нет ресурсов в инете. Спасибо за комментарий   -  person Zethuman    schedule 17.03.2021
comment
Итак, похоже, вы спрашиваете, что вы можете сказать переводчику Пирса. Вот почему вы говорите, что это идет в файле .f. К сожалению, я не знаком с этими упражнениями Пирса, поэтому ничем не могу помочь. Это кажется слишком специализированным для StackOverflow (но, возможно, нет, это классический учебник). Если вы проходите курс, вы можете попробовать спросить у профессора или ассистента.   -  person Jeffrey Scofield    schedule 17.03.2021
comment
Спасибо, это я и хотел сказать. Профессор не имеет возможности спросить по ряду причин, я подумал, что здесь кто-нибудь может помочь.   -  person Zethuman    schedule 17.03.2021


Ответы (1)


Вместо lambda, как в лямбда-исчислении, вы используете fun для кодирования чисел Черча в OCaml. Вы определяете числа как функции, которые принимают унарную функцию (с именем s для преемника) и базовое значение (z для нуля). Например, три это:

# let three = fun s z -> (s (s (s z)));;
val three : ('a -> 'a) -> 'a -> 'a = <fun>

Если вы хотите преобразовать это представление в целое число OCaml, вы определяете:

# let int_succ x = x + 1;;

Затем вы можете получить целочисленное представление OCaml three, вызвав его следующим образом:

# three int_succ 0;;
- : int = 3

Он эффективно вызывает int_succ последовательно для 0, самого внутреннего результата (т.е. 1) и т. д., пока вы не получите 3.

Но вы можете манипулировать этими числами в их церковном представлении следующим образом. Например, чтобы вычислить номер Черча-преемника произвольного номера оттока n:

# let succ n = fun s z -> (s (n s z));;

Мы должны вернуть число Черча, результат является функцией двух параметров, s и z. Он также принимает один вход, номер церкви n. В результате звонит s (n s z), а именно наследнику номера n. Например:

# (succ three) int_succ 0;;
- : int = 4

Точно так же мы можем определить add:

# let add x y = (fun s z -> (x s (y s z)));;
val add : ('a -> 'b -> 'c) -> ('a -> 'd -> 'b) -> 'a -> 'd -> 'c = <fun>

Здесь функция принимает два числа. Выражение (y s z) представляет собой вычисление, выполненное для числа y, и используется в качестве базового значения при применении x к (x s (y s z)). Если вы используете int_succ и 0 для s и z, вы можете видеть, что (y s z) будет увеличиваться от 0 столько раз, сколько раз закодировано y, а затем увеличиваться от этого значения столько раз, сколько раз закодировано x.

Например:

# let two = fun s z -> (s (s z)) ;;
val two : ('a -> 'a) -> 'a -> 'a = <fun>

Потом:

# let five = add two three;;
val five : ('_weak4 -> '_weak4) -> '_weak4 -> '_weak4 = <fun>

Обратите внимание, что типы слабы, вам не нужно слишком беспокоиться об этом, но это означает, что как только вы вызовете Five с заданными s и z, вы не сможете повторно использовать five с различные виды.

# five int_succ 0;;
- : int = 5

И вот, тип полностью известен:

# five;;
- : (int -> int) -> int -> int = <fun>
person coredump    schedule 17.03.2021
comment
Спасибо за ответ, но похоже, что это не ответ на мой вопрос. Я работаю с github.com/roehst/tapl-implementations/tree/master/ полный нетипизированный. Я понял, что вам ответили, но в моей ситуации там нет типов. У меня есть только логические значения и лямбда-исчисление. Пожалуйста, просмотрите код в ссылке, которую я отправляю. - person Zethuman; 18.03.2021
comment
Похоже, что приложение функции на этом нетипизированном языке принимает только один аргумент, вам может понадобиться добавить круглые скобки для вызова, например, (f x y) как ((f x) y). - person coredump; 18.03.2021