搜索树中的racket递归(回溯)

搜索树中的racket递归(回溯),racket,Racket,我的球拍语言有问题。我想在列表中找到目标状态。但在达到我作为参数给出的限制的那一刻,我得到了->函数调用:在开括号后应该是一个函数,但收到的却是空的。问题出在expand2中 我怎么在球拍上写这个 (定义(主启动限制) (let([结果(扩展起始限制)]) (写入结果) (定义(扩展状态限制) (条件((目标状态)(列表状态)) ((

我的球拍语言有问题。我想在列表中找到目标状态。但在达到我作为参数给出的限制的那一刻,我得到了->函数调用:在开括号后应该是一个函数,但收到的却是空的。问题出在expand2中

我怎么在球拍上写这个

(定义(主启动限制)
(let([结果(扩展起始限制)])
(写入结果)
(定义(扩展状态限制)
(条件((目标状态)(列表状态))
((<限制0')())
(其他
(让([儿童(下一个州)];;下一个州返回一份类似的清单((43)(23))
(let((结果(扩展2个子项(-限制1)))
(and result(cons state result));;(append result(cons state resultЮЮ))
(定义(扩展2个状态限制)
(如果(空?状态)
(列出国家)
((扩展(汽车状态)限制)
(expand2(cdr状态)限制)
(定义(下一个状态)
(删除空值)
(名单
(填写第一个州);;如果州是“(23)->”(43)
(填充第二个状态);;等等
(第一第二状态)
(第二个第一个状态)
(第一状态为空)
(第二状态为空)
谢谢

编辑:我试图写水壶的问题,你需要有第一个容量为2加仑的水壶,而你有容量为4加仑和3加仑的未测量水壶。例如,要启动程序u,请使用(main’(4 3)7。7是树的限制深度

如果(展开(汽车状态)限制)返回空,则

( (expand (car states) limit) 
        (expand2(cdr states) limit))

(empty…
相同,您将得到错误的
函数调用:在开括号后应该有一个函数,但收到空的
Racket有一个非常好的IDE,称为DrRacket。它将根据代码结构识别您正在编写的代码。当您编辑代码时,按CTRL+i将为您“修复”标识,所以请经常按它。在LISPy语言中插入的代码是不可读的

从您的原始格式中,不清楚
expand2
的定义是否在
expand
中的非法位置(本地定义位于顶部),但通过适当的缩进,您可以看到它在那里

代码中有很多奇怪的东西。一个是缺少括号,这使得该程序从一开始就无效

另一个事实是,您有两个应用程序,它们本身被括号包围:

((expand (car states) limit) (expand2 (cdr states) limit))
如果你把它与eg相比

(- 10)
您可以看到
(扩展(汽车状态)限制)
需要成为一个过程,就像变量
-
成为一个过程一样。这里您要么忘记了一个操作数。例如
(cons expr-1 expr-b)
或者如果有副作用,可能您需要
(begin expr-1 expr-2)


一旦应用程序没有语法错误,DrRacket就有了一个相当不错的调试器。您可以逐步检查代码,并找到其他bug。试试看

expand2

((expand (car states) limit)
 (expand2 (cdr states) limit))
这意味着您试图将递归调用的结果作为函数调用
expand
,但据我所知
expand
从未返回函数

你到底想在这个部门做什么

编辑:

虽然我仍然不完全理解您当前的代码应该如何工作,但我认为一些关于如何使用递归实现回溯的说明应该可以帮助您:

递归调用应该能够进入从当前状态开始的所有可能的分支。每次递归调用返回时,检查它是否返回了有效的最终结果-在这种情况下,您只需再次返回到下一个更高的级别-或者如果这是表示失败的特殊结果-在这种情况下,如果当前状态仍有分支,则进行下一次递归调用,或者,如果已经用尽了可能的分支,也可以返回特殊结果

编辑2:

下面是一些示例代码,希望能够澄清我上面解释的关于如何使用递归进行回溯的基本思想。有趣的是,Racket标准库函数
ormap
可以为我们完成大部分工作:

(define (backtrace state)
  (if (goal state)
      (list state)
      (let [[result (ormap backtrace (next-states state))]]
        (and result (cons state result)))))
搜索 使用回溯搜索嵌套结构[graph]通常需要队列、堆栈或类似结构来保存临时状态。在Lisps中,堆栈很容易,因为可以用
cons
将元素推到列表的前面,用
first
car
访问列表的第一个元素,用
rest
cdr
获取“弹出”列表。使用a提供了一种新的方法

处理状态 在函数样式中处理状态的标准方法是将状态作为附加参数传递。一种典型的方法是定义一个接受附加参数的内部函数,然后使用

示例代码 这是基于我对问题总体目标的理解。具体的输入和输出可根据您的需要进行调整:

#lang racket

(define (main start limit)

  (define (success? item limit)
    (equal? item limit))

  (define (inner start limit stack)
    ;; list? any? list? -> any? or null?
    ;; Returns limit on match, null on no match
    (cond 
      ;; There's nothing left
      [(and (empty? start)
            (empty? stack))
       null]
      ;; A list has been exhausted
      ;; So backtrack using the stack
      ;; As start state
      [(empty? start)
       (inner stack limit null)]
      ;; Otherwise look at the first item
      [else
       (let ((item (car start)))
         ;; Does the item match the limit?
         ;; **Remember the limit could be a list**
         (cond 
           ;; If it matches return the matching value
           [(success? item limit) item]
           ;; Otherwise if the item is a list
           ;; Push the elements of item onto the stack
           [(list? item)
            (inner (rest start)
                   limit
                   (append item stack))]
           ;; The item isn't a list and it doesn't match.
           [else (inner (rest start)
                        limit
                        stack)]))]))

  ;; Trampoline the inner function
  (inner start limit null))
样本输出
是的,我知道,但我不明白的是,我如何能够正确地写,并返回到以前的状态而不会出现任何错误。我不熟悉函数式编程范例。为了得到更好的答案,您需要提供更多信息。编辑您的问题并添加:1。每个函数的目的语句。2.函数的输入和输出示例。我想回溯并扩展下一个节点,当达到限制时,如果没有目标,则返回并扩展下一个节点branch@assasinx我编辑了我的答案,解释了如何使用递归实现回溯。如果你想让你自己的方法发挥作用,我只能帮助你,如果你更透彻地解释它是如何运作的
> (main '(1 2 3 (4 5) 6) '(4 5))
'(4 5)
> (main '(1 2 3 (4 5) 6) 6)
6
> (main '(1 2 3 (4 5) 6) 4)
4
> (main '(1 2 3 (4 5) 6) 8)
'()