Skip to content

Commit

Permalink
implement let* in terms of let
Browse files Browse the repository at this point in the history
  • Loading branch information
bennn committed May 27, 2017
1 parent a5e85af commit 204b80c
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 0 deletions.
1 change: 1 addition & 0 deletions index.scrbl
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@

@include-example{first-class-or}
@include-example{cross-macro-communication}
@include-example{let-star}
25 changes: 25 additions & 0 deletions let-star/let-star-test.rkt
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#lang racket/base
(module+ test
(require rackunit syntax/macro-testing syntax-parse-example/let-star/let-star)

(check-equal?
(let-star ([x 1] [x 2]) x)
2)

(check-equal?
(let-star ([x 0] [y (+ x 1)] [z (+ y 1)]) z)
2)

(check-equal?
(let-star ([a 1] [b 2]) a b)
2)

(check-exn exn:fail:syntax?
(λ () (convert-compile-time-error (let-star 3 4))))

(check-exn exn:fail:syntax?
(λ () (convert-compile-time-error (let-star ()))))

(check-exn exn:fail:syntax?
(λ () (convert-compile-time-error (let-star ([x 1] [y 2])))))
)
18 changes: 18 additions & 0 deletions let-star/let-star.rkt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#lang racket/base
(provide let-star)
(require (for-syntax racket/base syntax/parse))

(define-syntax (let-star stx)
(syntax-parse stx
[(_ ([x:id v:expr]) body* ...+)
#'(let ([x v])
body* ...)]
[(_ ([x:id v:expr] . bind*) body* ...+)
#'(let ([x v])
(let-star bind* body* ...))]
[(_ bad-binding body* ...+)
(raise-syntax-error 'let-star
"not a sequence of identifier--expression pairs" stx #'bad-binding)]
[(_ (bind*))
(raise-syntax-error 'let-star
"missing body" stx)]))
53 changes: 53 additions & 0 deletions let-star/let-star.scrbl
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#lang syntax-parse-example
@require[
(for-label racket/base syntax/parse syntax-parse-example/let-star/let-star)]

@(define let-star-eval
(make-base-eval '(require syntax-parse-example/let-star/let-star)))

@title{@tt{let-star}}

@; =============================================================================

Racket's @racket[let] binds identifiers simultaneously;
Racket's @racket[let*] binds identifiers in sequence.
For example:

@racketblock[
(let* ([a 1]
[b (+ a 1)])
b)]

behaves the same as a nested @racket[let]:

@racketblock[
(let ([a 1])
(let ([b (+ a 1)])
b))]

The @racket[let-star] macro implements @racket[let*] in terms of @racket[let].

@racketfile{let-star.rkt}

Note:
@itemlist[
@item{
The macro is recursive.
The use of @racket[let-star] in the second clause will later expand to
a sequence of @racket[let]s.
}
@item{
The pattern @racket[...+] matches one or more of the previous pattern.
}
]

@examples[#:eval let-star-eval
(eval:error (let* 1))

(eval:error (let* ([a 1])))

(let* ([a 1]
[b (+ a 1)]
[c (+ b 1)])
c)
]

0 comments on commit 204b80c

Please sign in to comment.