Skip to content

Instantly share code, notes, and snippets.

@apg
Created February 9, 2012 13:05
Show Gist options
  • Save apg/1779857 to your computer and use it in GitHub Desktop.
Save apg/1779857 to your computer and use it in GitHub Desktop.
let-values
;; Suppose you have this function partition which splits a list
;; in two as soon as the predicate p? returns true. It does not
;; include the value that the predicate succeeded on, but values
;; after it are included.
(define (partition cs p?)
(let loop ((l cs)
(accum '()))
(cond
((null? l) (values (reverse accum) '()))
((p? (car l)) (values (reverse accum) (cdr l)))
(else
(loop (cdr l) (cons (car l) accum))))))
;; scheme@(guile-user)> (partition (string->list "hello?world") (lambda (x) (char=? #\? x))))
;; $29 = (#\h #\e #\l #\l #\o)
;; $30 = (#\w #\o #\r #\l #\d)
;; It uses values, so we get two return values. No big deal, we can bind them using
;; `call-with-values`
;; scheme@(guile-user)> (call-with-values (lambda ()
;; (partition (string->list "hello?world") (lambda (x) (char=? #\? x))))
;; (lambda (x y)
;; (format #t "first: ~a\nsecond: ~a\n" x y)))
;; first: (h e l l o)
;; second: (w o r l d)
;; $31 = #t
;; That's very verbose though. We need one lambda to wrap up the values producer, and another
;; to unpack it. Surely we can do better!
;; So we define let-values:
(define-syntax let-values
(syntax-rules ()
((_ (bs producer) body ...)
(call-with-values (lambda () producer)
(lambda bs body ...)))))
;; scheme@(guile-user)> (let-values ((x y) (partition (string->list "hello?world") (lambda (x) (char=? #\? x))))
;; (format #t "first: ~a\nsecond: ~a\n" x y))
;; first: (h e l l o)
;; second: (w o r l d)
;; $32 = #t
;; let-values is just a macro that shuffles around the parameters and hides the boilerplate procedures that
;; needed to be created to use call-with-values. It also provides a familiar interface, by reusing the basic
;; premise of `let`
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment