(and (negative? (random 100)) (/ 1 0)) は #f を返します。それはどのように行うのですか?
i (define (∧ b₀ b₁) (if (not b₀) #f b₁)), (∧ (negative? (random 100)) (/ 1 0)) それでも「0 による除算」エラーが発生します。
スキームは厳密and
であるため、関数として直接定義することはできません。これは、関数の引数が関数に渡される前に常に評価されることを意味します。
and
ただし、マクロを使用して適切な短絡を定義できます。ラケットの最も単純なバージョンは次のとおりです。
(define-syntax-rule (my-and a b) (if a b #f))
syntax-rules
または、標準スキームにある which を使用した同等の形式:
(define-syntax my-and
(syntax-rules ()
[(_ a b) (if a b #f)]))
マクロは通常の機能ではありません。代わりに、コンパイル時に実行される構文変換です。コードでnew を使用するand
と、対応する式に「展開」されif
ます。そう:
(my-and #f (/ 1 0))
に変換されます
(if #f (/ 1 0) #f)
プログラムが実行される前に。if
は言語に組み込まれているため、これは正しい動作をします。
マクロは関数ではないため、引数として渡すことはできません。したがって、直接使用して折り畳みを書くことはできませんand
-ラムダにラップする必要があります。
元の にもっと忠実にするために、マクロを再帰的にすることで、任意の数の引数を取るようにand
定義できます。my-and
マクロで「残りのパラメーター」を定義するには、特別な...
キーワードを使用します。
(define-syntax my-and
(syntax-rules ()
[(_) #t]
[(_ a) a]
[(_ a b ...) (if a (my-and b ...) #f)]))
代わりにRacket#lang lazy
や Haskell などの遅延言語を使用している場合は、ここでマクロを使用する必要はありません。直接定義することができますand
:
#lang lazy
(define (and a b) (if a b #f))
またはHaskellで:
and a b = if a then b else False
通常の機能として、正しい動作をします。これをフォールドに渡すことができ、 !and
に遭遇するとすぐにリストの評価を停止することさえできます。False
見てみましょう:
Prelude> foldl and True [True, False, error "fail"]
False
( error
Haskell では のようにエラーが発生し1/0
ます。Haskell は静的に型付けされるため、引数はブール値である必要があり、直接and
使用することはできません。)1/0
ほとんどの言語と同様に、Scheme の論理AND
は短絡評価を使用します。つまり、左側のオペランドが true の場合にのみ右側のオペランドが評価されます。左のオペランドが false の場合、式の結果は右のオペランドの値に関係なく false でなければならないため、左のオペランドが false と評価された場合、右のオペランドをまったく評価せずにすぐに false を返します。
正確には、仕様の言語は次のとおりです (私は R5RS のセクション 4.2.1 ですが、これは仕様の改訂間で変更される可能性が高い領域ではありません)。
(and <test
1>
... )
式は
<test>
左から右に評価され、偽の値 (セクション 6.3.1 を参照) に評価される最初の式の値が返されます。残りの式は評価されません。
ブール値のショートカット。"and" の最初の引数は false と評価されるため、結果は false でなければならず、2 番目の引数を評価する理由はありません (したがって、エラーが発生します)。