Powered by SmartDoc

論理演算と条件判定

真偽値を返す関数

lispの関数には、条件判断を行い、その結果として、真偽値(真[条件が成立するという値... Tになる]と、偽[条件が成立していないという値... NILになる] )を返す関数があります。

  1. 数値比較:数値の比較の結果を真偽値として返します。
    関数名 名称 引数の個数 関数の値
    = 等しい 2 2つの引数の値が等しければ真[T]、そうでなければ偽[NIL](以下同様)
    /= 等しくない 2 2つの引数の値が異なれば真[T]
    < 小さい 2 一つ目の引数の値が二つ目の引数の値より小さければ真
    <= 以下 2 一つ目の引数の値が二つ目の引数の値以下(等しいか小さい)ならば真
    > 大きい 2 一つ目の引数の値が二つ目の引数の値より大きければ真
    >= 以上 2 一つ目の引数の値が二つ目の引数の値以上(等しいか大きい)ならば真
  2. 属性判定:引数の属性の判定結果を真偽値として返します。
    関数名 名称 引数の個数 関数の値
    zerop ゼロ判定 1 引数の値が0ならば真
    numberp 数判定 1 引数の値の形式が数値形式ならば真
    plusp 正判定 1 引数の値が正の数ならば真
    minusp 負判定 1 引数の値が負の数ならば真
    null NIL判定 1 引数の値がNILならば真
    atom atom判定 1 引数の値がatomならば真(19)
    listp list判定 1 引数の値がlistならば真
  3. Symbolの比較:数値以外も比較可能です。
    関数名 名称 引数の個数 関数の値
    eq 同一性比較( identity ) 2 二つ引数の値が同じ物ならば真
    equal 同一形式( equality ) 2 二つ引数の値が同じ表現ならば真(21)
[演習1.7.1]
記の関数に関して、成立する場合としない場合の例を考え、実際に、その例を試してみなさい。
  1. NILは、atomであると同時に、Listでもある唯一の存在です。
  2. eqとequalの二つの区別はし難いかもしれませんが、例えていえば、「双子は、equal (同じように見える)だが、eq (同一人物)ではない」というところでしょうか..。

    一般に、eqなら、equalが常に成立するのですが、その逆は、成立するという保証がありません。

    実際、atomは、equalならeqが言えるのですが、listの場合は、equalだからといって、eqが言えないことがほとんどです。(偶然言えることもありますが.. )。

    結論からいえば、「普通は、equalを使うのが無難」で、まあ、eqは使わないということでしょうか。

論理演算

与えられた真偽値から新しい真偽値を計算する演算を論理演算と呼びます。

関数名 名称 引数の個数 関数の値
and かつ(論理積) 0...(26) 引数のどれかの値がNILなら偽[NIL]。そうでなければ、NIL以外(27)
or または(論理和) 0... すべての引数の値がNILなら偽[NIL]。そうでなければ、NIL以外(28)
not でない(否定) 1 引数の値がNILなら真(29)
[演習1.7.2]
上記の関数に関して、成立する場合としない場合の例を考え、実際に、その例を試してみなさい。
[演習1.7.3]
andやorに、全く引数を与えない場合にどうなるかを考え、その上で、実際に、xlispでの計算を行って、その考えが正しいかどうかを確かめなさい。
  1. 引数は何個でも書けます。
  2. 実際には、最後の引数の値になります。
  3. 実際には、NILでなかった最初の引数の値になります。
  4. nullと全く同じ働きをします。

条件分岐

真偽値を利用して、挙動を変えたい時があります。その場合に利用するのが、以下の関数です。

関数名 名称 引数の個数 関数の値
if もし 2か3(32) 一つ目の引数がNILなら、全体の値は、三つ目の引数の値そうでなければ、二つ目の引数の値(33)
cond 多条件分岐 0 ..

condの引数は「二つの要素を持つList」の形を想定しています。condの値は、次のように計算されます。

最初のList引数の最初の要素の値がNILでないならば、そのListの二番目の値、そうでなければ、次の要素の最初の要素の値を調べる、以下、同様。

[演習1.7.4]
次の点を確かめなさい。
  1. (+ 1 2 3)はどうなるか?
  2. (+ 1 NIL 3)はどうなるか?
  3. (+ 1 (+ 1 NIL) 3)はどうなるか?
  4. (if NIL (+ 1 NIL) 3)はどうなるか?
  5. (if T (+ 1 NIL) 3)はどうなるか?
  6. (and T (+ 1 NIL) 3)はどうなるか?
  7. (or T (+ 1 NIL) 3)はどうなるか?
[演習1.7.5]
引数が正の数かどうかを判定する関数pos-numを作りたい。すなわち、「引数が正の数ならば、TそうでなければNILを返す」とする。この時、次の問いに答えなさい。
  1. なぜ、関数pluspでは駄目なのだろうか(ヒント: (plusp T)の結果は? )
  2. if, numberp, pluspを利用して、pos-numを定義しなさい。
[演習1.7.6]
絶対値の計算を行う関数myabsを作りなさい。すなわち、「引数が正の数ならそのまま、負の数ならその符号を変えたもの、そうでなければ0を返す」関数である。もちろん、数以外の引数が与えられた場合でも「エラーにならず、0を返す」ものとします。
[演習1.7.7]

myifという関数を次のように定義した

(defun myif (condition then else) ( if condition then else ) )

すなわち、「myifは、ifの私家版」としたい。これは巧く行くだろうか?

巧く行かないとしたら、問題となる例はどのような場合か?

[演習1.7.8]
ifとcondの関係を知るために、次の問いに答えなさい。
  1. (if a b c)と書かれている場所をifの代わりに、condを利用して、書き変えるとしたら、どのようにすれば良いか?
  2. [演習1.7.5]のpos-numを、ifの代わりにcondを利用して書き換えなさい。
  3. (少し難しい)

    同様に、if, condの代わりに、andとorの両方を利用して、pos-numを定義してみなさい。

[演習1.7.9]
二番目の引数の値によって、挙動を変える次のような関数mcalcを定義しなさい。
  1. 引数は3つで、いずれも数である。
  2. 最初の引数はと三つめの引数は任意の数が入り、これが計算の対象となる。
  3. 二つ目の引数は、整数で次のような意味がある。
    1. 値が1の時、関数の値は、一つ目と三つ目の和になる。
    2. 値が2の時、関数の値は、一つ目と三つ目の差になる。
    3. 値が3の時、関数の値は、一つ目と三つ目の積になる。
    4. 値が4の時、関数の値は、一つ目と三つ目の商になる。
    5. その他の時、関数の値は、0になる。
  1. 引数が2つの場合は、3つ目の引数としてNILが与えられたと同じように振舞います。(つまり一つ目の引数がNILなら無条件にNILになる)
  2. より正確には、「引数を評価した値」となります。実は、次のcond (や、実は、andやorなどや、defunなど.. )もそうですが、ifは、普通の関数とは異なり、呼び出される前に引数の値が評価されません(逆に、われわれがdefunで定義する関数は、全て、呼び出される前に引数の評価が行われています)。評価が行われるのは、関数が呼び出された後に、今回の例にあるように、必要に応じて、積極的に評価が行われます。従って、逆にいえば、引数の中には評価されないままのものも生じる可能性があるということです。

    これは、奇異に感じるかもしれませんが、このような仕組みの必要性は、「演習1.7.4」をやってみれば解ると思います。