DrRacket:如何在复合变量中存储“相等检测器”?

时间:2016-12-20 23:19:49

标签: oop lisp

如果您愿意,请将标题更改为更合适的标题。

我正在以面向对象的程序的形式制作一些东西,这里有一个名为world的化合物:

(define-struct world (var1 var2 var3 loo))

其中“var”1到3是Number并代表一些世俗变量,如温度,湿度等。loo是“对象列表”的缩写,对象定义如下:

(define-struct obj (id act))

其中idInteger并且是对象的ID,而act是另一种化合物:

(define-struct act (trigger command))

以后会解释triggercommandString,表示将在程序的其他部分解析的命令。

这是我的问题:我希望trigger成为一个表达式,如果世界上的某些变量是以一种方式返回true,例如,我想这样做,以便{ {1}}和var1具有相同的值,发出命令var2。对此的“无条件”代码将如下所示:

"start-rain"

如果难以理解,可以使用带注释的版本:

(define (get-commands loo0)
   (local [(define (fn-for-loo todo rsf)
              (cond [(empty? todo) rsf]
                    [else (fn-for-obj (first todo)
                                      (rest todo)
                                      rsf)]))

           (define (fn-for-obj obj todo rsf)
              (if (true? (act-trigger (obj-act obj)))
                  (fn-for-loo todo (cons (act-command (obj-act obj)) rsf))
                  (fn-for-loo todo rsf)))]
      (fn-for-loo loo0 empty)))

我的问题是我不知道(define (get-commands loo0) ;;-------------------------------------------------This function returns (listof String), it uses local for tail-recursion (local [(define (fn-for-loo todo rsf) ;;------------------------------------rsf is result-so-far accumulator, it is (listof String) (cond [(empty? todo) rsf] ;;-------------------------------------rsf returned as final output of entire function when all objects are checked [else (fn-for-obj (first todo) ;;--------------------------if some objects are unchecked, pass objects to fn-for-obj to check the first (rest todo) rsf)])) (define (fn-for-obj obj todo rsf) ;;--------------------------------receiving one object of attention, other unchecked object and result-so-far (if (true? (act-trigger (obj-act obj))) ;;-----------------------if the trigger returns true... (fn-for-loo todo (cons (act-command (obj-act obj)) rsf)) ;;--add current object's command to the list of commands and pass on to fn-for-loo (fn-for-loo todo rsf)))] ;;----------------------------------if trigger returns false, pass on without modification to rsf (fn-for-loo loo0 empty))) ;;---------------------------------------------this kick-starts the local functions 应该是什么,它必须是根据trigger中的变量返回Boolean的内容。当然,世界的变量可以通过词法范围或直接引用来访问,但是如何在world中编写trigger的表达式,并且在程序知道世界变量可用之前?

我正在尝试这样的事情:

object

但编译器说“var1未定义”

1 个答案:

答案 0 :(得分:1)

如果你想访问世界各地,你需要传播世界:

(define (get-commands w loo0)
   (local [(define (fn-for-loo todo rsf)
              (cond [(empty? todo) rsf]
                    [else (fn-for-obj (first todo)
                                      (rest todo)
                                      rsf)]))

           (define (fn-for-obj obj todo rsf)
              (if ((act-trigger (obj-act obj)) w)
                  (fn-for-loo todo (cons (act-command (obj-act obj)) rsf))
                  (fn-for-loo todo rsf)))]
      (fn-for-loo loo0 empty)))

(define OBJ1
  (make-obj 1
            (make-act (lambda (w) (= (world-var1 w) (world-var2 w)))
                      "start-rain")))

(define OBJ2
  (make-obj 2
            (make-act (lambda (w) (= (world-var1 w) (world-var3 w)))
                      "go-home")))

true?谓词不是很有用。)

测试:

(define w0 (make-world 1 1 1 (list OBJ1 OBJ2)))

> (get-commands w0 (world-loo w0))
'("go-home" "start-rain")

许多人更愿意使用标准的高阶函数:

(define (get-commands w loo0)
  (foldl (lambda (o rs) (if ((act-trigger (obj-act o)) w)
                            (cons (act-command (obj-act o)) rs)
                            rs))
         '()
         loo0))

请注意,您的代码会按照列表中对象的相反顺序生成命令。

如果您希望它们按相同顺序排列,则可以执行以下操作:

(define (get-commands w loo0)
  (foldr (lambda (o rs) (if ((act-trigger (obj-act o)) w)
                            (cons (act-command (obj-act o)) rs)
                            rs))
         '()
         loo0))

或者这个:

(define (get-commands w loo0)
  (let ((triggered (filter (lambda (o) ((act-trigger (obj-act o)) w)) loo0)))
    (map (lambda (o) (act-command (obj-act o))) triggered)))