miniKanren: How to define #s and #u?
Asked Answered
P

3

5

In miniKanren, succeed can be defined as (define succeed (== #t #t)), and fail can be defined as (define fail (=== #t #f)). But what about #s and #u as short forms of succeed and fail, as they appear in The Reasoned Schemer?

(define #s succeed) produces an error in Racket:

Welcome to Racket v7.2.
> (require Racket-miniKanren/miniKanren/mk)
> (define #s succeed)
; readline-input:2:8: read-syntax: expected `(`, `[`, or `{` after `#s` [,bt
;   for context]
#<procedure:...iniKanren/mk.rkt:337:4>
; readline-input:2:18: read-syntax: unexpected `)` [,bt for context]

I have the feeling that this has something to do with reader macros.

How can I define #s for succeed and #u for fail in Scheme and also in Racket?

I am using the canonical miniKanren implementation for Scheme and the canonical miniKanren implementation for Racket.

Phosphoresce answered 21/7, 2019 at 13:51 Comment(2)
short answer might be, it doesn't matter, as it might be too hard to achieve for not much of a gain. :)Whitener
These were intended as typesetting conventions for the convenience of the book writer. These were not intended to be things that the programmer following along would key in character for character.Unstoppable
P
4

Identifiers in Racket can not begin with #. It is simple to bind the identifiers s and u. Redefining the meaning of #s and #u is not as simple, since it needs to happen in the reader. Normally #something signals to reader that something special is to be read. The input (foo bar) will be read as a list, #(foo bar) will be read as a vector, and #s(foo bar) will be read as a structure. You can read about the standard syntax here:

https://docs.racket-lang.org/reference/reader.html?q=%23s#%28mod-path._reader%29

Now if you want to change the meaning of #s and #u you need to look at readtables. Each time the reader sees an # it consults a readtable to see how to handle the following characters. Since reading happens before parsing/expansion and evaluation, you can't change the reader simply by calling a function in your program. You will need to either use the #reader extension mechanism or create your own language.

For more on readtables: https://docs.racket-lang.org/reference/readtables.html?q=reader-macro

The Guide has an example of how to use reader extensions: https://docs.racket-lang.org/guide/hash-reader.html

Philippe answered 22/7, 2019 at 15:30 Comment(0)
T
2

I solved all the book using

(define succeed
  (lambda (s)
    `(,s)))
(define SUCC succeed)

(define fail
  (lambda (s)
    '()))

On the other side, you should consult the source code provided by Friedman & Byrd. I solved it using mit-scheme -- no specific feature of racket is used, R6RS is enough.

Therewith answered 23/7, 2019 at 9:59 Comment(0)
P
2

For Racket, #s and #u can be defined as such (reference: Using Racket for The Reasoned Schemer):

;; #s for succeed.
(current-readtable
  (make-readtable (current-readtable)
                  #\s
                  'dispatch-macro
                  (lambda (ch port src line col pos) succeed)))

;; #u for fail.
(current-readtable
  (make-readtable (current-readtable)
                  #\u
                  'dispatch-macro
                  (lambda (ch port src line col pos) fail)))

Note that this only works in the REPL.

This defines #s and #u by modifying the readtable.

For Scheme, adding read syntax is defined in SRFI-10 sharp-comma external form, but the resulting #,() forms are probably awkward for most tastes. For Scheme, it is best to just define s and u because there is currently no portable way to define #s and #u.

Phosphoresce answered 26/7, 2019 at 7:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.