2015-07-21 8 views
1

Я могу сделать простые сокращения лямбда-исчисления, однако я не могу понять, как делать те, которые получают «currying».Сокращение исчисления лямбда

Эти два примера, которые я не могу понять:

  1. (((lambda x . (lambda y . (j y))) j) m)
  2. ((lambda p . (p j)) (lambda x . (q x)))
+0

Всего комментариев: 2) не является примером для каррирования, потому что там нет серии абстракций. Он просто сводится к '' 'p j''' в два этапа. –

ответ

1

Предполагая, что вы говорите о просто типизированного лямбда-исчисления с помощью вызова по стратегии оценки стоимости, Первый уменьшает это нравится:

  1. (((лямбда х. (Лямбда-у (JY).)) К) м) - заменить x для j
  2. ((лямбда-у (JY)) м.) - заменить y для m
  3. (JM)
  4. здесь , вы застряли ...

Обычно не применяется правило сокращения для применения переменной к переменной. Обычно мы используем систему типов, чтобы гарантировать, что для любой хорошо типизированной программы, когда мы оцениваем, мы никогда не «застреваем», как это было на шаге 3.

Каррирование не должно создавать дополнительной сложности, чем то, что вы, возможно, уже видели. В общем, стратегия образует что-то вроде формы e1 e2 ... en, вы можете думать об этом как (((e1 e2) e3) ... en). Затем вы уменьшите e1 e2, что должно дать лямбду, которую вы, чем оцениваете, применяете к e3 и так далее.

Я позволю вам понять, как это упражнение.

+0

Система типов не запрещает приложениям от переменной до переменной, она только предотвращает самоприменение. Например. '' '(\ x y.x) (f 0) 0''' является типом с 0, x, y типа t и f типа t-> t. Даже вложения не исключаются: '' 'f (gf)' '' можно ввести с помощью f: '' 's-> t''' и g:' '' (s -> t) -> s''' , –

+1

Я не утверждал, что целью системы типов является исключение программ, которые будут применять переменные к переменным. Мое утверждение состояло в том, что цель системы типов заключается в том, чтобы убедиться, что при проверке хорошо типизированной программы она не «застревает», как это было на шаге 3. Я признаю, что моя формулировка, возможно, была несколько неоднозначной и я с радостью исправлю это. Однако, чтобы сказать, что система типов ** ТОЛЬКО ** предотвращает самоприменение, не является правильным утверждением. – Matt

+0

Вы правы, часть «только предотвращает» неверна :) –

2

Замечание Ошибка при оценке, она сводится к j m, поэтому часть о самоприложении не имеет отношения к делу.

Карринг является наблюдение, что вы можете просмотреть серию лямбда-абстракций по-разному:

В математических терминах ((lambda x . (lambda y . (j y))) может быть дано имя, а затем записать в виде: f(x,y) = j(y). В вашем примере вы бы оценили f(m,j) = j(j). Итак, что произойдет, если у нас нет обоих аргументов для f? Мы не можем его полностью оценить, но мы можем определить новую функцию g (y) = f (j, y), где мы просто вставляем первый аргумент. Эта пошаговая оценка функции называется частичной оценкой или каррированием.

В исчислении лямбда эти два аспекта выглядят абсолютно одинаково. Если вы хотите применить оба параметра к своему термину, вы начинаете с первого аргумента:

Ваша начальная функция f (m, j): (((lambda x . (lambda y . (j y))) j) m) сводится к g (j): ((lambda y . (j y))) j. Когда мы продолжим нашу оценку (мы все равно можем применить нашу функцию к j), мы достигнем j (j): j j. Теперь мы больше не можем применять какие-либо правила сокращения, поэтому мы можем увидеть j j в результате наших вычислений. То, что наш результат - приложение, прекрасно, но что он применяется к себе, является чем-то особенным.

(остальное не имеет отношения к выделки больше, но само-приложение, которое мосты к тому, что писал)

@ Matt

Возможно, следует объяснить, что это означает: функция J получает в качестве аргумента. С помощью этого вы можете реализовать рекурсию. Знаменитый Y combinator Y: (lambda x . f x x) делает именно это: если вы оцениваете Y Y, то есть (lambda x . f x x) Y, вы вычисляете f (Y Y). Когда вы снова оцените внутренний Y Y, вы вычисляете f f (Y Y) и так далее. Это как раз рекурсивное применение функции f. Побочным эффектом является то, что для некоторого f оценка никогда не прекратится (уже если вы используете функцию идентификации (lambda x.x)).

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

E.g. предположим, что x имеет тип int, то в приложении f x, f должен быть такого типа, который принимает переменную типа int и вычисляет результат, скажем, типа string. Тогда мы можем написать тип f как int -> string. Тип f x - string, так как это мы получаем, когда оцениваем f на x.

Абстракции создают новую функцию. Например, (lambda x . x) нуждается в аргументе типа int и производит термин типа int, то есть он имеет тип int -> int.

Но теперь самоприложение вроде j j больше не работает: скажем, внутренний j имеет тип t. Тогда внешний j должен быть типа t -> t. Единственный способ сделать эту работу состоит в том, что ваш тип - это бесконечное гнездование t, которое обычно запрещено.

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

+0

Вы говорите, что '(((lambda x. (Lambda y. (Jy))) j) m)' сводится к '((lambda y. (jy))) j'. Это неверно. Вы должны подставлять 'x' для' j', который будет уменьшаться до '((lambda y. (J y)) m)', как я имею в своем ответе. Попробуйте запустить '(((\ x -> (\ y -> 1 + y))) 1) 3' через GHC, он выйдет до 4, а не 3 ... – Matt

+0

Argl вы правы, спасибо, что указали его вне. Я неправильно указал скобки ('' '(\ x -> (\ y -> 1 + y) 1) 3'''). Я исправлю свой ответ, когда у меня снова будет доступ к Интернету. –

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

  • Нет связанных вопросов^_^