2016-12-20 3 views
0

Пожалуйста, измените заголовок на что-то более подходящее, если хотите.DrRacket: Как я могу хранить «детектор равенства» в составной переменной?

Я делаю что-то в виде объектно-ориентированной программы, есть соединение называется world, как определено здесь:

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

Где «вар» 1 через 3 является Number и представляет некоторые мирские переменные, такие как температура, влажность и т.д. loo является аббревиатурой «список объектов», объекты определены ниже:

(define-struct obj (id act)) 

Где id это Integer и идентификатор OBJE кт и act еще одно соединение:

(define-struct act (trigger command)) 

Где trigger будет объяснено позже и command является String, представляющий команду, которая будет решена в других частях программы.

Вот моя проблема: Я хочу trigger быть выражение, которое возвращает true если некоторые переменные мира в Certan образом, к примеру, я хочу сделать так, чтобы, когда var1 и var2 имеют одинаковое значение, выдается команда "start-rain". «Imgainary» кусок кода для этого будет выглядеть следующим образом:

(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 и до того, как программа узнает, что мировые переменные будут доступны?

Я пытаюсь что-то вроде этого:

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

но компилятор говорит «var1 не определен»

ответ

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)))