miniKanren:如何定义#s和#u?

Posted

技术标签:

【中文标题】miniKanren:如何定义#s和#u?【英文标题】:miniKanren: How to define #s and #u? 【发布时间】:2019-11-29 17:01:40 【问题描述】:

在miniKanren中,succeed可以定义为(define succeed (== #t #t))fail可以定义为(define fail (=== #t #f))。但是#s#usucceedfail 的缩写形式,它们出现在The Reasoned Schemer 中呢?

(define #s succeed) 在 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]

我感觉这与阅读器宏有关。

如何在 Scheme 和 Racket 中为 succeed 定义 #s 和为 fail 定义 #u

我正在使用canonical miniKanren implementation for Scheme 和canonical miniKanren implementation for Racket。

【问题讨论】:

简短的回答可能是,没关系,因为它可能太难实现而没有太大的收获。 :) 【参考方案1】:

Racket 中的标识符不能以# 开头。绑定标识符su 很简单。重新定义#s#u 的含义并不那么简单,因为它需要发生在读者身上。通常#something 会向读者发出信号,表示要阅读一些特别的东西。 输入(foo bar) 将被读取为列表,#(foo bar) 将被读取为向量,#s(foo bar) 将被读取为结构体。您可以在此处阅读有关标准语法的信息:

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

现在如果你想改变#s#u 的含义,你需要查看readtables。 每次读者看到# 时,它都会查阅一个可读表以了解如何处理以下字符。由于读取发生在解析/扩展和评估之前,您不能简单地通过调用程序中的函数来更改读取器。您将需要使用 #reader 扩展机制或创建您自己的语言。

有关 readtable 的更多信息:https://docs.racket-lang.org/reference/readtables.html?q=reader-macro

指南中有一个如何使用阅读器扩展的示例: https://docs.racket-lang.org/guide/hash-reader.html

【讨论】:

【参考方案2】:

我用

解决了所有的书
(define succeed
  (lambda (s)
    `(,s)))
(define SUCC succeed)

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

另一方面,您应该咨询 Friedman & Byrd 提供的the source code。我使用 mit-scheme 解决了这个问题——没有使用球拍的特定功能,R6RS 就足够了。

【讨论】:

【参考方案3】:

对于 Racket,#s#u 可以这样定义(参考: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)))

请注意,这只适用于 REPL。

这通过修改readtable 来定义#s#u

对于Scheme,添加读取语法在SRFI-10 sharp-comma external form 中定义,但生成的#,() 形式对于大多数人来说可能很尴尬。对于 Scheme,最好只定义 su,因为目前没有可移植的方式来定义 #s#u

【讨论】:

以上是关于miniKanren:如何定义#s和#u?的主要内容,如果未能解决你的问题,请参考以下文章

如何阅读 nm 命令:nm 选项 -T 和 -U(未定义)是啥意思?

阐明不同 minikanren 实现中的搜索算法

图 DB 与 Prolog(或 miniKanren)

为啥 miniKanren 中的“disj”在 Scheme 中有效,而在 Racket 中无效?

#define S64_MIN 在 linux 数据类型中是如何定义的?

为啥 miniKanren 的名字总是以 `o` 结尾?