I was reading the Goblins white paper when I got stuck on the blog post example in section 3.3. More specifically, within the definition of the spawn-post-and-editor
function, it seems like the get-content
method of ^post
is able to reference the editor
object that is only defined towards the end of spawn-post-and-editor
. I am not sure how this is able to work. Is there some aspect of Scheme or Guile Scheme’s semantics that I am missing?
Nice catch - what you’re missing is that it’s a closure. The post
and editor
variables are both enclosed in the scope of the spawn-post-and-editor
function.
It’s the same reason this code works:
(define (test-func)
(define (inner)
x)
(define x 5)
inner)
…and evaluates to this:
scheme@(guile-user)> ((test-func))
$7 = 5
What you’re seeing are recursive definitions. ^post
, ^editor
, post
, and editor
are all defined within spawn-post-and-editor
and it’s no problem in Scheme for ^post
to refer to editor
within the procedure body. Perhaps this rewrite to use letrec
will make it more clear to you:
(define* (spawn-post-and-editor #:key title author body)
(letrec ((^post
;; The public blogpost
(lambda (bcom)
(methods
;; fetches title, author, and body, tags with '*post* symbol
((get-content)
;; assign data-triple to the current data
(define data-triple ($ editor 'get-data))
;; return tagged with '*post*
(cons '*post* data-triple)))))
(^editor
;; The editing interface
(lambda (bcom title author body)
(methods
;; update method can take keyword arguments for
;; title, author, and body, but defaults to their current
;; definitions
((update #:key (title title) (author author) (body body))
(bcom (^editor bcom title author body)))
;; get the current values for title, author, body as a list
((get-data)
(list title author body)))))
;; spawn and return the post and editor
(post (spawn ^post))
(editor (spawn ^editor title author body)))
(values post editor))) ; multi-value return of post, editor
Thanks for the answer, Jonathan.
Thanks for the explanation, David. That does help to clear things up. Would it be possible for your explanation to be added to a future version of the paper? I think this would be really helpful for other non-native Schemers like myself.
Also, would it have been equally valid to change the order of the definitions to be ^editor
, editor
, ^post
and then post
? If I understand correctly, perhaps this way it would be clearer that, in this particular case, there does not need to be any recursive dependency between ^post
and editor
(although I suppose the ^editor
constructor itself would still necessarily be recursive).
I think your second suggestion of just changing the definition order would be the better thing to do as the references aren’t actually recursive. That would save us from explaining a finer detail of Scheme. Filed an issue here Change variable definition order in spawn-post-and-editor procedure in spritely-core (#15) · Issues · spritely / Spritely Papers · GitLab