如果项目不在计划中的lst中

时间:2012-10-12 16:30:55

标签: scheme

我正在研究无上下文的语法,我有一个返回(语法的终值)的函数

例如: 我有非终端功能导致(A B),从呼叫说((A猫)(B happy np)(A B伤心)) 所以技术上A和B是语法的非终端。现在我希望能够得到终端(猫快乐np伤心)

(define terminals
  (lambda (lsts)
    (cond
     ((null? lsts) lsts)
     ((not(member? (car(car lsts)) (n-terminals lsts)))
      (cons (car(car lsts)) (terminals (car (cdr lsts)))))
     (else (terminals (cdr lsts))))))

PS:以上描述了n端子的功能。 会员?是一个布尔函数,如果一个项是列表的成员,则返回true,否则返回false。 我的函数返回一个空的lst。我在这里缺少什么?

1 个答案:

答案 0 :(得分:1)

问题在于找到终端符号时的操作。这里确实存在两个不同的问题。

首先,您只需查看每个规则的第一个符号。您的lsts变量是一系列规则;每个规则都是符号列表。因此(car (car lsts))会为您提供第一条规则的第一个符号。

第二个问题是你找到终端符号后如何递归。通常,您会传递terminals列表。但是,在您找到终端符号(即以(member? ...)开头的符号)后的情况下,您将其传递给(car (cdr lsts))。我们知道lsts是一个列表列表。所以(cdr lsts)也是一个列表列表(当然还是一个空列表)。这意味着(car (cdr lsts))只是普通列表。

我认为解决这个问题的最简单方法是将其分解为两个函数。首先,编写一个从规则获取终端的函数。也就是说,不要只关注整个输入((A cat) (B happy np) (A B sad)),而是像(B happy np)那样关注一个规则。所以编写一个函数,给定(B happy np),给你(happy np)。接下来,编写一个函数,将此函数应用于lsts中的每个规则,并组合所有输出。 (您可能会发现append函数在这里很有用。)

将其写入两个单独的函数应该可以更容易地考虑问题。生成的代码也将更简单,更容易阅读,这是一个奖励。

另外,风格无关紧要:你可以(而且应该)写

(define foo
  (lambda (args) ...))

as

(define (foo args)
  ...)

这两个表达式具有相同的含义,但第二个表达式更易于阅读和使用。

编辑:正如我在评论中所说,我会首先计算非终端列表,并将其用于一次执行一行的函数。你可以通过嵌套你的两个函数并利用Scheme的词法范围来使这个变得简单:

(define (terminals rules)
  (let ((non-terminals (n-terminals rules)))
    (define (helper rule) ; this takes a rule and returns all its terminal symbols
       ... ; you can use non-terminals in here
    )
    ; now here you have to call helper on every rule and combine the results
  ))

另一种选择是将其分解为两个非嵌套的函数,并传入一个非终端符号列表:

(define (terminals-from-rule rule non-terminals)
  ... ; implement, using non-terminals as the list of non-terminal symbols
)
(define (terminals rules)
  ... ; here you need to calculate the list of non-terminals and pass
      ; it into each call to terminals-from-rule along with the rule.
)