问题
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.
回答1:
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
回答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.
回答3:
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
.
来源:https://stackoverflow.com/questions/57133822/minikanren-how-to-define-s-and-u