2013-06-21 27 views

回答

8

and不是一個函數,它是一個宏,所以你不能像函數一樣傳遞它。

and是宏的原因,是啓用短路的行爲。你可以讓你自己的非短路版本:

(define (my-and . items) 
    (if (null? items) #t 
     (let loop ((test (car items)) 
       (rest (cdr items))) 
     (cond ((null? rest) test) 
       (test (loop (car rest) (cdr rest))) 
       (else #f))))) 

my-and可以apply使用。

爲了便於比較,這裏就是宏(這確實做短路)看起來像:

(define-syntax and 
    (syntax-rules() 
    ((and) #t) 
    ((and test) test) 
    ((and test rest ...) (if test 
          (and rest ...) 
          #f)))) 
10

克里斯小丑,年輕的answer是正確的,但還有另外一點我想強調。標準and運算符是一個宏,它通過(基本上,如果不是完全的話)將(and a b c)轉換爲(if a (if b C#f) #f)來延遲其參數的評估。這意味着如果a爲false,則不會對bc進行評估。

我們也有定義and-function這樣(and-function a b c)評估abc的選項,而當值全部爲真,則返回true。這意味着所有的a,bc被評估。 and-function具有很好的屬性,您可以將它作爲函數傳遞,因爲它是一個函數。

目前仍然似乎少了一種選擇:一個and-function-delaying-evaluation返回回當且僅當ab,並c所有返回true,但不評估,例如,bc如果a產生錯誤的。實際上,這可以通過功能and-funcalling-function來實現,該功能要求其參數爲功能列表。例如:

(define (and-funcalling-function functions) 
    (or (null? functions) 
     (and ((car functions)) 
      (and-funcalling-function (cdr functions))))) 

(and-funcalling-function 
(list (lambda() (even? 2)) 
     (lambda() (odd? 3)))) 
; => #t 

(and-funcalling-function 
(list (lambda() (odd? 2)) 
     (lambda() (even? 3)))) ; (even? 3) does not get evaluated 
; => #f 

使用宏和這個成語,我們實際上可以實現一些與標準and語義:

(define-syntax standard-and 
    (syntax-rules() 
    ((standard-and form ...) 
    (and-funcalling-function (list (lambda() form) ...))))) 

(macroexpand '(standard-and (odd? 2) (even? 3))) 
; => 
; (and-funcalling-function 
; (list (lambda() (odd? 2)) 
;  (lambda() (even? 3)))) 

採取遠離這一切的教訓,當然是,你可以有一個and類似的功能,你可以傳遞並仍然得到延遲評估;你只需要通過在函數中包裝東西來延遲評估,並讓類似的函數調用這些函數來產生值。 (在Scheme中,這可能是一個使用promise的機會。)

+1

@ ChrisJester-Young感謝您的編輯!我知道我提到了翻譯,但我從來沒有做過翻譯。現在帖子更符合現在的問題。謝謝! –

相關問題