Why not implement `let` in terms of a lexically closed` define`?

I have been working with lisp-family languages ​​for several years and feel that I have a pretty good understanding. I am writing my own lisp right now (like a mod, of course), but almost completely avoiding re-implementing the same templates as Scheme, Common lisp and friends. The only feature I always thought odd, all the options are let( letrec, flet, labels, let*...).

Say that the past from the past was not carried over in the lisp implementation, I would just like to write things like:

(let ((x 7)
      (y 8)
      (z (* x y)))
  (str "x * y * z = " (* x y z)))

And in a similar way, I would like to write:

(let ((odd? (lambda (n) (if (zero? n) false (even? (dec n)))))
      (even? (lambda (n) (if (zero? n) true (odd? (dec n)))))
  (odd? 7))

I could implement both of these options quite efficiently, simply using the definition inside the lambda body. Sorry clojure -circuit-hybrid code:

(defmacro let (bindings & body)
  `((lambda ()
      ,@(map (lambda (name-value) (cons 'define name-value)) bindings)
      ,@body)))

, , . , , , (define x expression) (define y expression) .

, , ? - ? let, , , , , . , , let*.

+4
2

(har har) R5RS letrec, R6RS R7RS - letrec*. , , - , letrec*.

, , , . let let* , letrec letrec*.

? , let , letrec :

(let ((x 1)
      (y 2))
  (let ((x (+ x y))
        (y (- x y)))
    (format #t "x = ~a, y = ~a~%" x y)))

(+ x y) (- x y) x y. , x 3, y -1.

let* , , :

(let ((x 1)
      (y 2))
  (let* ((x (+ x y))
         (y (- x y)))
    (format #t "x = ~a, y = ~a~%" x y)))

x , let, y x x ( - y, y ). , x 3, y 1.

letrec letrec* , x y. / .

letrec letrec* , , letrec , ; letrec* .


let, Racket, :

#lang racket
(define-syntax test-let
  (syntax-rules ()
    ((_ let)
     (let ((x "outer x")
           (y "outer y")
           (p (lambda (x y label)
                (printf "~a: x = ~s, y = ~s~%" label x y))))
       (let ((before (p x y "before"))
             (x (begin
                  (p x y "during x")
                  "inner x"))
             (between (p x y "between"))
             (y (begin
                  (p x y "during y")
                  "inner y"))
             (after (p x y "after")))
         (p x y "body"))))))

:

> (test-let let)
before: x = "outer x", y = "outer y"
during x: x = "outer x", y = "outer y"
between: x = "outer x", y = "outer y"
during y: x = "outer x", y = "outer y"
after: x = "outer x", y = "outer y"
body: x = "inner x", y = "inner y"

> (test-let let*)
before: x = "outer x", y = "outer y"
during x: x = "outer x", y = "outer y"
between: x = "inner x", y = "outer y"
during y: x = "inner x", y = "outer y"
after: x = "inner x", y = "inner y"
body: x = "inner x", y = "inner y"

> (require rnrs/base-6)
> (test-let letrec)
before: x = #<undefined>, y = #<undefined>
during x: x = #<undefined>, y = #<undefined>
between: x = #<undefined>, y = #<undefined>
during y: x = #<undefined>, y = #<undefined>
after: x = #<undefined>, y = #<undefined>
body: x = "inner x", y = "inner y"

> (require rnrs/base-6)
> (test-let letrec*)
before: x = #<undefined>, y = #<undefined>
during x: x = #<undefined>, y = #<undefined>
between: x = "inner x", y = #<undefined>
during y: x = "inner x", y = #<undefined>
after: x = "inner x", y = "inner y"
body: x = "inner x", y = "inner y"

, let.: -)

+8

define ( ) letrec R5RS a letrec* R6RS R7RS. letrec*, ( undefined).

(let ((x 10))
  (letrec ((x x))
     x)) ;; returns some undefined value

(let ((x 10))
  (let ((x 'undefined))
     (let ((tmpx x)) ;; notice x is already shadowed by the new binding
        (set! x tmpx)
        x))) ;; returns some undefined value

, , , . odd?. x x, .

, , (let ((x 10) (y 20)) ...) - , ((lambda (x y) ...) 10 20), let* - let (let* ((x 10) (y 20)) ...) => (let ((x 10)) (let ((y 20)) ... ))). let letrec, letrec* letrec ( , , )

10 , , define, 20 10 . , , Scheme , , , letrec*

+2

Source: https://habr.com/ru/post/1532748/


All Articles