miniKanren: How to define #s and #u?

我的未来我决定 提交于 2021-02-10 00:23:53

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!