Порядок вычисления лямбда-выражений на схеме

Доктор Рэкет пользователь.

Вот два выражения:

((лямбда(х)(+ х 1))3)

((лямбда(х)(+ х 1)2)3)

Первое — это лямбда-выражение, которое принимает один вход и увеличивает его на 1. Таким образом, оно принимает 3 в качестве операнда и делает (лямбда (3) (+ 3 1), что равно 4.

Второй очень неоднозначен для меня, так как он оценивается как 2, и я не могу понять порядок его оценки. Я знаю, что он должен что-то делать со скобками, которые меняют порядок, но я не могу понять, как это сделать. Очевидно, что он даже не суммирует «1» и «x», просто по какой-то причине выдавая 2 в качестве вывода. Мне не хватает базового понимания оценки. Заранее спасибо!


person Dmitrii    schedule 07.11.2017    source источник
comment
Используйте алгебраический степпер (ногу) в DrRacket, чтобы ответить на эти вопросы. Степпер позволяет выполнять пошаговое вычисление выражений (а также возвращаться назад!)   -  person soegaard    schedule 08.11.2017
comment
что можно сделать, если опция шага назад не работает из-за ошибки?   -  person X10D    schedule 03.04.2020


Ответы (2)


Как указано в документах Racket:

Определение функции может включать несколько выражений для тела функции. В этом случае при вызове функции возвращается только значение последнего выражения. Другие выражения оцениваются только для некоторых побочных эффектов, таких как печать.

Например:

(define (f x)
  (+ 1 1)              ;; evaluates to 2, but not returned    
  (= 3 4)              ;; evaluates to false, but not returned
  0                    ;; evaluates to 0, but not returned
  1000                 ;; evaluates to 1000, but not returned
  pi                   ;; evaluates to pi, but not returned
  "I am a string")     ;; last expression; evaluates and returns "I am a string"

и

(f 10)
=> "I am a string"
(f 'okay)
=> "I am a string"
(f pi)
=> "I am a string"

То же самое происходит в вашей последней лямбде, в результате чего:

((lambda (x) (+ x 1) 2) 3)
=> ((lambda () (+ 3 1) 2))
=> ((lambda () 4 2))   ;; last expression is 2, so output 2
=> 2
person assefamaru    schedule 07.11.2017

Тело всех производных форм от lambda оценивается слева направо в порядке, как в begin. Все выражения, кроме последнего, оцениваются только для побочного эффекта, а результат самого последнего выражения будет результатом вашей функции:

((lambda (x)
   (+ x 1) ; not in tail position. no effect so it's dead code
   2)      ; the evaluation of 2 will be the result every time
 3) ; argument, only used by dead code.

На самом деле он производит сумму, а затем отбрасывает ее, чтобы вычислить последнее выражение. Единственное хорошее применение мертвому коду — согреться зимой. Пример более разумного использования большего количества выражений в теле:

(define (hypopotemus a b)
  (define (square x)                ; Not in tail position, creates 
    (* x x))                        ; a function as side effect.
  (sqrt (+ (square a) (square b)))) ; Tail expression calculates the result

И так как это упоминает порядок оценки. В то время как аргументы функций оцениваются строго слева направо в #lang racket во всех отчетах Scheme, таких как #!r6rs, реализация (например, рэкет) может выбирать любой порядок. например.

((lambda (a b c) (display "d")) 
 (display "a")
 (display "b")
 (display "c")

Хотя приведенный выше код всегда печатает «abcd» в #lang racket, это только один из 6 возможных результатов в схеме, поскольку вы не знаете, в каком порядке аргументы оцениваются первым, средним и последним, и печать будет происходить в порядке оценки. Я знаю, что рэкет, конечно, оценивает свой код схемы слева направо, в то время как Икарус делает это в обратном порядке.

person Sylwester    schedule 07.11.2017