2011-07-08 22 views
6

To wydaje się proste pytanie; być może jest to tak proste, że trudno znaleźć szukanie, które znajdzie odpowiedź. W Scheme (konkretnie implementacja Guilla, jeśli to robi jakąkolwiek różnicę), w jaki sposób mogę ocenić coś, co zostało cytowane?kontrolowanie oceny w schemacie (podstęp)

Oto, co próbuję zrobić.

Po prostu muszę upewnić się, że funkcja, którą definiuję, ocenia jej argumenty w określonej kolejności, ponieważ efekty uboczne powodowane przez ocenę jednego argumentu zależą od oceny innych argumentów. Jednak Scheme mówi, że argumenty można oceniać w dowolnej kolejności, więc chcę ręcznie wymusić je, cytując argumenty, a następnie ręcznie je oceniając w żądanej kolejności.

Wydaje się, że „eval” jest powinien robić to, co chcę, ale to ma dwa problemy:

  1. Jego użycie jest zalecane, więc czuję się jak nie powinno być lepszym sposobem, aby osiągnąć to, co Chcę tu zrobić.
  2. W schemacie okazuje się, że eval przyjmuje drugi parametr, którym jest środowisko. To mnie myli. Chcę, żeby to było w tym samym środowisku, w którym pojawia się instrukcja, dlaczego więc potrzebowałem drugiego parametru? Czy to możliwe? Grałem trochę z evalem i wydaje się, że niektóre implementacje wymagają innych parametrów (np. Mit-scheme nie wie nawet co to jest (interakcja-środowisko) !!!)

Próbowałem innych sztuczek , jak budowanie lambda:

(list 'lambda '() '(car (b c))) 

, ale wydaje się, że musiałoby to zostać ocenione w celu wygenerowania procedury. Próbowałem również:

(list lambda '() '(car (b c))) 

ale to zwraca „prymitywny-wbudowaną-makro”, który nie działa.

Edit: Wygląda makro zadziała na kolejność oceny kontroli: (defmacro test1 (ab) `(początek, B, A))

Odpowiedz

1

Jeśli trzeba ocenić strukturę listy (zagnieżdżonych list z cytowanymi symbolami, które reprezentują tekst programu Scheme), wtedy powinieneś użyć eval. Program wymaga podjęcia środowisko jako drugi argument, nawet jeśli jest on obecny środowiska:

(eval '(+ x y) (interaction-environment)) 

Jeśli po prostu trzeba robić swoje obliczenia w określonej kolejności, można wymusić kolejność oceny dla efektów ubocznych za pomocą begin, let lub po prostu treść funkcji.Określają one sekwencję ocen:

(let ((x 42)) 
    ; eval with effects #1 
    (display x) 
    ; eval with effects #2 
    (display (+ x 1))) 

Edit: Jeśli trzeba mieć sparametryzowanego bloku kodu, w którym można przekazać wyrażeń unevaluated a następnie zmusić ich oceny w jakimś konkretnym celu, a następnie można użyć jednego z te techniki:

  • makro (jak już pan wspomniał, tylko dla kompletności):

    > (defmacro test1 (a b) `(begin ,b ,a)) 
    > (test1 (display 2) (display 3) 
    32 
    
  • Opóźniona obliczeń (Special składni schemat dla oceny leniwe):

    > (define (test1 a b) (begin (force b) (force a))) 
    > (test1 (delay (display 2)) (delay (display 3))) 
    32 
    
  • A regularne lambda abstrakcję i stosowania

    > (define (test1 a b) (begin (b) (a))) 
    > (test1 (lambda() (display 2)) (lambda() (display 3))) 
    32 
    
+0

Jak działa makro, jeśli potrzebuję zmiennej liczby argumentów? '(defmacro test1 (a. b) \' (begin, b, a)) 'nie działa, ponieważ b jest teraz listą. Muszę jakoś splatać go na początku, ale różne próby takie jak '\' (rozpocząć (jeśli (para?, B) (test1, b)), a)) nie działają. – Michael

+0

również, nie mogę użyć '(defmacro test1 (a. B) \' (begin (apply begin, b), a)) 'ponieważ nie mogę zastosować makra. – Michael

+0

ten, którego przegapiłeś, to '(test defmacro1 (a. B) \' (begin, (cons 'begin b), a)) ' –

8

eval jest całkowicie błędne narzędziem prostu zmieniając kolejność oceny argumentów. Utwórz makro zamiast:

;; (my-fun e1 e2) 
;; Just calls my-real-fun, but evaluates e2 before e1 
(define-syntax my-fun 
    (syntax-rules() 
    [(my-fun e1 e2) 
    ;; let* has guaranteed order of evaluation 
    (let* ([y e2] 
      [x e1]) 
     (my-real-fun x y))])) 

(define (my-real-fun x y) ....) 

Jeśli musisz, użyj defmacro.

0

Byłeś na właściwej drodze, mijając lambda. Jeśli masz

(define (f x y z) ...) 

... wtedy można nazwać tak:

(f 
    (lambda() a) 
    (lambda() b) 
    (lambda() c)) 

ten wezwie f ze wszystkimi argumentami (a, b, c) w unevaluated formie. Wewnątrz f masz pełną moc, aby wybrać kolejność, w jakiej je ocenisz. Jedyna różnica polega na tym, że musisz jawnie wywołać (x), (y) i (z) i przechwycić ich wartości w instrukcjach podobnych do define lub let. To pozwala upewnić się, że efekty uboczne zdarzają się tylko raz.

Tutaj nie ma potrzeby używania makr. Btw, nie martw się o używanie wielu lambdas wszędzie, są one bardzo tanie.