プロが教えるわが家の防犯対策術!

(define (find i . elements)
(if (eq? i (car elements)) 'Matched! (find2 i (cdr elements))))

(define (find2 i elements)
(if (eq? i (car elements)) 'Matched! (find2 i (cdr elements))))

上記を一つのfunctionにまとめることはできないでしょうか?
現在二つに分けている理由は(eq? i (car elements))が偽だったときに実行される(cdr elements)がリスト(例 '(a b c))なので、そのままfindを呼んでしまうとfindは(i . elements)を取るため、elementsが'((a b c))となってしまうからです。find2を使い、そのような「リストの中のリスト」を作らないようにしています。

find2を使わず一つにまとめられる方法はないでしょうか?お願いします。

A 回答 (4件)

疑問が2つあります。



1.eq?でホントにいいの?

等価テストでeq?用いていますが、これはホントにポインタ使ってアドレス比較を行います。
つまり、例えばbと言う要素を(a b c)のから探したい、と言う場合、失敗する可能性がありますよ(いや、明らかに失敗するでしょう)。
と言うのも、bと'(a b c)の中のbは同じメモリにあるとは限らないから、です。
通常、推奨されるシンボル同士の比較にはeqv?を使います。こっちの方が若干判定条件が緩いです。また、比較対象が「数値限定」だったら=を使った方が良いですね。

2.find内定義でレストパラメータを利用している意味が明確じゃない。

必須パラメータの数がまず足りないのでは、と思いますね。
.(ドット)の後は、使用者が「入力しなくても構わないもの」と言うのが前提です。
そうなると、

(find 3)

の挙動はどう考えておられるのでしょうか?
これは、単に

(find 3 1 2 3 4 5 6 7 8 9)

と言うような入力を考慮してる設計でしょ?意味があるのかちょっと分からんのです(大体、見やすいか?とか思いますしね)。
平たく言うと、find2だけの設計で充分じゃないのか、と言うような気もします。
    • good
    • 0

あああああ。

つい書いちゃったよ。

;;; ここから

(define (find i element . elements)
 (if (eqv? i element)          ;必須パラメータ同士が eqv? だったら
   'Matched!              ;Matched! を返すのが基本動作
   ;; ローカル手続き loop を作る
   (let loop ((elm elements))  ;レストパラメータのリストを elm に束縛
     (and (pair? elm)      ;レストパラメータが null じゃない事を確かめる
       (or (find i (car elm)) ;トップレベルのfindをレストパラメータ無しで呼び出すか
         (loop (cdr elm))))))) ;loop を elements の cdr に対して再帰呼び出し

;;; ここまで

;;; 実行例

> (find 3 3)
Matched!
> (find 0 1)
#f
> (find 3 3)
Matched!
> (find 0 1 2 3 4 5 6 7 8 9)
#f
> (find 3 1 2 3 4 5 6 7 8 9)
Matched!
> (find #\d #\a #\b #\c #\d #\e #\f)
Matched!
> (find #\a #\b #\c #\d #\e #\f #\g)
#f
>
    • good
    • 0

しまった。

もう一本書いてしまった。

ええと、memvと呼ばれる組み込み手続きがSchemeにはあります。
これは次のようにして使います。

> (memv 3 '(1 2 3 4 5 6 7 8 9))
(3 4 5 6 7 8 9)
> (memv 0 '(1 2 3 4 5 6 7 8 9))
#f
>

memvは、ある要素がリストの中にあるかどうか探し、あった場合はそれをcarとしたリストを、無かった場合は#fを返します(判定にはeqv?ば使われています)。
つまり、殆どfindの挙動と同じなんですよ。従って、レストパラメータが形作るリストに対して、素直にこれを適用しても結果は変わらない、と言う事です。

;;; ここから

(define (find i element . elements)
 (and (or (eqv? i element) ;必須パラメータ同士を比較するか
      (and (pair? elements) ;レストパラメータが null じゃない事を確認した後
         (memv i elements))) ;i が elements 内にあるかどうか判定する
    'matched!)) ;正しかったら matched! を返す

;;; ここまで

;;; 実行例

> (find 0 1)
#f
> (find 3 3)
matched!
> (find 0 1 2 3 4 5 6 7 8 9)
#f
> (find 3 1 2 3 4 5 6 7 8 9)
matched!
> (find #\d #\a #\b #\c #\d #\e #\f)
matched!
> (find #\a #\b #\c #\d #\e #\f #\g)
#f
>
    • good
    • 0

おっと#3の訂正。



memvは空リストに対しても正常に動作しますね。

> (memv 3 '())
#f
>

と言うことはレストパラメータの中身がどうなのか、確認せんでもエエって事ですね。

(define (find i element . elements)
 (and (or (eqv? i element)       ;必須パラメータ同士を比較する
      (memv i elements))      ;i が elements 内にあるかどうか判定する
    'matched!))           ;正しかったら matched! を返す。

;;; 実行例

> (find 0 1)
#f
> (find 3 3)
matched!
> (find 0 1 2 3 4 5 6 7 8 9)
#f
> (find 3 1 2 3 4 5 6 7 8 9)
matched!
> (find #\d #\a #\b #\c #\d #\e #\f)
matched!
> (find #\a #\b #\c #\d #\e #\f #\g)
#f

;;; ここまで

なんで、これが一番コードとしては短いかな?
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!