• 締切済み

schemeでリストの中にリストができてしまう。

(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を使わず一つにまとめられる方法はないでしょうか?お願いします。

みんなの回答

回答No.4

おっと#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 ;;; ここまで なんで、これが一番コードとしては短いかな?

回答No.3

しまった。もう一本書いてしまった。 ええと、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 >

回答No.2

あああああ。つい書いちゃったよ。 ;;; ここから (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 >

回答No.1

疑問が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だけの設計で充分じゃないのか、と言うような気もします。

関連するQ&A