- 締切済み
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を使わず一つにまとめられる方法はないでしょうか?お願いします。
- みんなの回答 (4)
- 専門家の回答
みんなの回答
- cametan_42
- ベストアンサー率62% (162/261)
おっと#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 ;;; ここまで なんで、これが一番コードとしては短いかな?
- cametan_42
- ベストアンサー率62% (162/261)
しまった。もう一本書いてしまった。 ええと、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 >
- cametan_42
- ベストアンサー率62% (162/261)
あああああ。つい書いちゃったよ。 ;;; ここから (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 >
- cametan_42
- ベストアンサー率62% (162/261)
疑問が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だけの設計で充分じゃないのか、と言うような気もします。