何が問題ですか?
重要な注意点は->
、if-else に (矢印) を使用することです。式がある場合S -> T ; U
、S
が評価され、変数が含まれている場合、コードに副作用が生じる可能性があります。より明確にするために、いくつかの例を実行してみてください。
?-[A,B] #:: 1..10,
(A #= 3) or (B #= 3),
((A #> 3 or B #>3) ->
write("expression 1")
;
write("expression 2")
).
A
andの値はB
決定されないため、条件は常に true であり、 の値がexpression 1
出力されます。また、結果は次のとおりです。
A = A{1 .. 10}
B = B{1 .. 10}
There are 6 delayed goals.
Yes (0.00s cpu)
ご覧のとおり、and の境界はA
将来B
の式に保留されているため変更されません。
次に、別の例を試してください。
?- [A,B] #:: 1..10,
(A #= 3) or (B #= 3),
((A #> 3 or B #>3) ->
write("expression 1")
;
write("expression 2")
),
A = 3. % this line is added
の値A
が決定さA #> 3
れるので真ではありませんが、どうB
ですか?それは 3 に等しいか、3 より大きいですか? 先ほど言ったように、条件部分が実行されます! したがって、最後の制約B
は ですB #> 3
。の実行に加えてwrite("expression 1")
、結果は次のとおりです。
A = 3
B = B{4 .. 10}
Yes (0.00s cpu)
最後の例は次のとおりです。
?- [A,B] #:: 1..10,
(A #= 3) or (B #= 3),
((A #> 3 or B #>3) ->
write("expression 1")
;
write("expression 2")
),
A = 3,
B = 3. % this line is added
また、この例expression 1
では が出力され、結果は次のようになります。
No (0.00s cpu)
これは、矢印の頭と常にexpression 1
実行されるためです。
1 つの解決策;
は、次のような演算子を使用することです。
[A,B] #:: 1..10,
(
(A = 3, B = 3, write('expression 21'))
;
(A = 3, B #> 3, write('expression 11'))
;
(A #> 3, B #> 3, write('expression 12'))
;
(A #> 3, B = 3, write('expression 13'))
),
A = 3,
B = 5.
上記のコードの結果は次のとおりです。
A = 3
B = 5
Yes (0.00s cpu, solution 1, maybe more)
そしてそれは印刷します:
expression 21 expression 11
これは最初のブランチがダウンしたことを意味しますが、失敗して自動的にバックトレースされ、次のケースに進みます! 次のケースが適用されると、すべてが成功します。