こんな感じのラケットでやってみた
> (apply and '(1 2 3))
. and: bad syntax in: and
> (and 1 2 3)
3
誰かがこれについてアイデアを持っていますか?
Chris Jester-Young の答えは正しいですが、強調したい点がもう 1 つあります。標準演算子は、(正確ではないにしても本質的に) に変換するand
ことによって、その引数の評価を遅らせるマクロです。これは、ifが false であり、評価されないことを意味します。(and a b c)
(if a (if b c #f) #f)
a
b
c
、、およびを評価し、値がすべて true の場合に true を返すand-function
ような を定義するオプションもあります。これは、 、、およびのすべてが評価されることを意味します。 関数であるため、関数として渡すことができるという優れたプロパティがあります。 (and-function a b c)
a
b
c
a
b
c
and-function
まだ欠けているように見えるオプションが 1 つあります。 anは、 、、およびすべてが trueand-function-delaying-evaluation
を返す場合にのみ return を返しますが、それは評価されません。たとえば、and ifは false を生成します。これは、実際には、引数が関数のリストである必要がある関数で行うことができます。例えば:a
b
c
b
c
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
受け渡しが可能で遅延評価を取得できる - のような関数を持つことができるということです。物事を関数でラップし、and
-like 関数がそれらの関数を呼び出して値を生成できるようにすることで、評価を遅らせるだけで済みます。(Scheme では、これは promise を使用する機会になるかもしれません。)