如果您愿意,请将标题更改为更合适的标题。
我正在以面向对象的程序的形式制作一些东西,这里有一个名为world
的化合物:
(define-struct world (var1 var2 var3 loo))
其中“var”1到3是Number
并代表一些世俗变量,如温度,湿度等。loo
是“对象列表”的缩写,对象定义如下:
(define-struct obj (id act))
其中id
是Integer
并且是对象的ID,而act
是另一种化合物:
(define-struct act (trigger command))
以后会解释trigger
,command
是String
,表示将在程序的其他部分解析的命令。
这是我的问题:我希望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未定义”
答案 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)))