1

In their book "The Seasoned Schemer", Felleisen and Friedman introduce the try function. According to http://community.schemewiki.org/?seasoned-schemer, this function can be defined as

(define-syntax try
  (syntax-rules ()
    ((try var a . b)
     (letcc success 
       (letcc var (success a)) . b))))

where letcc is defined as

(define-syntax letcc 
  (syntax-rules () 
    ((letcc var body ...) 
     (call-with-current-continuation 
       (lambda (var)  body ... ))))) 

Now, while I understand what try does and how it can be used, I am having trouble to follow the formal definition of it. What exactly is the meaning of the dot in the application of letcc to success and (letcc var (success a)) . b in the lines

(letcc success 
       (letcc var (success a)) . b)

of try? Or maybe asked differently: Which part of the definition of try establishes that try is evaluated to b if var is called in a?

Edit 1: Sorry, the definition of letcc was incomplete. Added the missing first line.

Edit 2: The following code can be run in Racket.

(define-syntax letcc
   (syntax-rules ()
                 ((letcc var body ...)
                  (call-with-current-continuation
                    (lambda (var)  body ... )))))

 (define-syntax try
   (syntax-rules ()
                 ((try var a . b)
                  (letcc success
                         (letcc var (success a)) . b))))

(try var (+ 1 1) 4)
; output: 2

(try var (var '(2)) 4)
; output: 4
Flux
  • 9,805
  • 5
  • 46
  • 92
J. Hauser
  • 115
  • 1
  • 9
  • please paste a complete working code. But you can use `unsyntax` in mit-scheme to see how the macro expander desugared the syntax. – alinsoar Feb 19 '20 at 14:16

3 Answers3

2

I'm not an expert on the intricacies of Scheme macro syntax, but I think an equivalent definition of try is:

(define-syntax try 
  (syntax-rules () 
    ((try var a b ...) 
     (letcc success 
       (letcc var (success a)) b ...))))

I find this much easier to read for sure.

(try e <a> <b> <c>) (either version, at least in Racket) then expands to

(letcc success
  (letcc e
    (success <a>))
  <b> <c>)))

So, then, when <a> is being evaluated, e is a continuation which returns its arguments from the inner letcc form, where they're ignored. If e is invoked that's where you end up and then <b> and <c> get evaluated in the normal way (I've only put more than one thing there because I can, and it deals with the whole . ... thing). if e isn't invoked during the evaluation of <a>, then success is invoked, and it's also a continuation which then returns the result of evaluating <a> from the whole form.

At least I think that's what happens.


Below is a chunk of Racket which I used to test I understood things.

(module+ test
  (require rackunit))

(define-syntax let/cc 
  (syntax-rules () 
    ((let/cc var body ...) 
     (call-with-current-continuation 
       (lambda (var) body ... ))))) 

(define-syntax try 
  (syntax-rules () 
    ((try var a b ...) 
     (let/cc success 
       (let/cc var (success a)) b ...))))

(module+ test
  (check-eqv?
   (try fail (+ 1 1) 4)
   2)

  (check-eqv?
   (try fail (fail '(2)) 4)
   4)

  (check-eqv?
   (try fail
        (begin 1 (fail) (error "failed to fail"))
        4 5 6)
   6))
Will Ness
  • 70,110
  • 9
  • 98
  • 181
1

Syntax rules is pattern matching. A dot indicates the car and cdr of a pair just like rest arguments in lambda / define:

(define (my-list . args)
  args)

A list is just nested pairs. eg. (1 2 3) is just fancy way of displaying (1 . (2 . (3 . ()))).

So (this is random symbols in a list) will match (try var a . b) by try matching this, is matches var, random matches a, and (symbols in a list) matches b.

When you see the same in the expansion it means the code should splice the match after the dot. Eg (var . b) with the previous example becomes (is symbols in a list). It is similar to having b ... but cheaper for the system.

Sylwester
  • 47,942
  • 4
  • 47
  • 79
  • Thanks; unfortunately, that is not what I am asking. I understand what the dot in the pattern `(try var a . b)` means but my question is about the dot two lines below that pattern. – J. Hauser Feb 19 '20 at 14:42
  • Thanks again, the last paragraph now answers my question about the dot in the expansion, i.e. that it is a splicing instruction. Do you happen to know where this expansion rule is explained in any of the Scheme language references? – J. Hauser Feb 20 '20 at 08:22
  • 1
    @J.Hauser not an instruction. If you give `'(a . b)` as code to the reader it will do a `(cons a b)` either in the compiler or runtime. The replacements having `(a b)` would mean `(cons a (cons b '()))` while `(a . b)` would be `(cons a b)` and when the reader has read the syntax-rule it is already consed. Thus during the expansion it just replaces the symbols it finds verbatim copying the structure with the "bindings" of the code. [The reference doesn't use much time on `.` at all.](http://www.r6rs.org/final/html/r6rs/r6rs-Z-H-14.html#node_sec_11.19) – Sylwester Feb 20 '20 at 10:53
1

Let us try and see what happens. I am using mit-scheme.

File try.scm:

(define-syntax letcc
  (syntax-rules ()
     ((letcc var body ...)
      (call-with-current-continuation
          (lambda (var)  body ... )))))

(define-syntax try
  (syntax-rules ()
     ((try var a . b)
      (letcc success
        (letcc var (success a)) . b))))

(try var (+ 1 1) 4)

(try var (var '(2)) 4)

First step: you compile the file:

> (sf "try")

This will generate the try.bin.

Second step, print the desugared syntax:

> (pp (unsyntax (fasload "try")))


;Loading "try.bin"... done
 ................
 (call-with-current-continuation
  (lambda (success)
    (call-with-current-continuation 
        (lambda (var) (success (+ 1 1))))
    4))
 (call-with-current-continuation
  (lambda (success)
    (call-with-current-continuation 
        (lambda (var) (success (var '(2)))))
    4)))

Now you see explicitly what is executed, hence the result.

In the case of (try var (+ 1 1) 4) you jump out 2 nested calcc, as you call success with value 2, while in the (try var (var '(2)) 4) you jump out 1 level and the 4 from the sequence of the 1st continuation will be returned.

Will Ness
  • 70,110
  • 9
  • 98
  • 181
alinsoar
  • 15,386
  • 4
  • 57
  • 74