#(define test
(case-lambda
(( x y :key zzzz ) (print (list "ZZ"x y zzzz) ))
(( x y :key qqqq ) (print (list "QQ" x y qqqq) )) ) )
#このようにkeyで定義を変えたい場合にはどうしたらいいのでしょうか・・・case-lambdaではうまくいかないのです。
#case-lambdaは引数の数でしか分岐できません。定義はひとつにしといて中で値を見て分岐するんじゃだめですか。
#なるほど。そうなんですね。keyを多用するもので、keyで分岐する手続きが簡単になればいいなあと思ったのです。
#上に書いてある例だと同じ:keyが出てきますけど、これは実際には:fooが来たときと:barが来たときで分岐したい、とかそういうことですよね?
#(hoge x y :a 12 :b 13) , (hoge x y :c 1234)のような呼び方に応じた定義をしたいわけです。
#match-lambdaを使うとかでは?
#(use util.match)
(define test
(match-lambda*
(( x y z) (print (list "0" x y z) ) )
(( x y :a aa) (print (list "ab" x y aa) ))
(( x y z :b bb) (print (list "cd" x y bb) ))
) )
#なるほど。
#keyにデフォルトを設定するとなると、また別の仕掛けがいるわけですね。
#(use util.match)
(define test
(match-lambda*
(( x y z) (print (list "0" x y z) ) )
(( x y :a aa :b bb) (print (list "ab1" x y aa) ))
(( x y :b bb :a aa) (print (list "ab2" x y aa) ))
(( x y z :b bb) (print (list "cd" x y bb) ))
(( x y z :c cc) (print (list "ef" x y cc) ))
) )
キーワードの順番に反応してしまいます・・・
#省略できないキーワードの組み合わせを一種の型として扱えないかなとか考えたのでした・・・
#MOP でなんとか出来るかも。
##keyを順不同にしたいなら、パターンマッチ系統はちょっと使い辛いと思います (任意の並びを許すマッチ、というのも前に書いたことあるけど、汎用化するのは面倒なんで)。そもそもキーワード引数って、本来の関数の動作を少し修飾するもの、って感じなので、キーワード引数の違いで定義を差し替えてしまいたいという場面がいまいち思いつかないんですが、もうちょい具体的な例はあるでしょうか。
#uriからひとつのページをよんで、概要とデータを抜いてくる関数があるのですが、これを拡張して、複数のページを読んで概要とデータを抜いてくるパラメータもつけたい。概要、データを抜くためのxpath定義は同じで、データの出処がひとつのページか、連続するページということになります。連続するページを指定する方法として、ジェネレータを指定します。
#ひとつのページを読むときには、単一のページを読む関数を与えます。
#いま、いろいろ考えてみたのですが、線分や円弧のパラメータ指定にも使えるような気がします。
#(draw-line :s hoge :e foo ) , (draw-line :s hoge :kakudo foo :nagasa bar) のような・・・
#複素数の指定とか、(complex-hogehoge :real a :imag b) (complex-hogehoge :arg a :abs b)みたいな。
##うーん、具体的に見てみないとはっきりとは言えませんが、それを聞いた感じだけだと別関数にする方が綺麗じゃないかと感じます。後者の、本質的に同じものに複数の指定方法がある、という場合ならまだキーワード引数でわけるのはありかなと思いますが、通常のキーワード引数で受けといて中で分岐してもいいような? 共通の処理もあるんですよね (共通の処理が全く無いのなら、なおのこと別関数で良いような。)
#そうそう、必須のキーワード引数というのは、たまに私もやったことがあるような気がしますが、あまり良いAPIじゃないと思います。必須なら必須引数にすれば良いので。(オブジェクトシステムのmakeに渡す値についてはキーワードって決まってるので、初期化時に必須の引数でもキーワードで渡すことになりますが)
#まあでもMLのラベル付き必須引数みたいなもの、と考えることもできるか。
#上記のリンクのread-and-map$の引数、get-raw だけが違って、あとは同じなので、同じ関数にしようかなと思ったのでした。
#引数に共通するものがあるかどうかではなく、関数の動作とインタフェースに共通部分が多いかどうかで判断すべきだと思います。引数の処理がだぶるならそこは共通関数に括り出して処理すればいいだけですし。型を書き下してみて同型にならなかったら別関数に分けた方が綺麗になることが多いかな、と私は感じます。
#同型ってのは全く同じ型ってことじゃなくて何らかのパラレルがあるってこと。例えば基本の動作として、X -> (X -> Y) -> Y の関数と X' -> (X' -> Y) -> Y の関数があったらこれをまとめるのはありそうだけど、[X] -> (X -> Y) -> [Y] というのがあったらこれは(いくら他のオプショナルな引数が共通でも) 最初の基本関数の上に組み立てられるものとして別関数になってた方がいいよね、みたいな。
#X を一つの要素しかない [X]とみなしてしまえば同じかなあとか思ったのでした。
#[X] -> (X -> Y) -> Yです。concatenateしてしまうので。
#はは。Common Lispではよく「単一の要素のリストのところに要素そのものを渡しても良いよ」ってやるんですが、Scheme書いてる時は私はもうちょい型を意識しがちで、その両者を同一視するのは私はなるべく避けるかなあ。
#いや、昔はそんなに意識してなかったかも。Haskellやってからだんだん気にするようになったかもしれない。今の話題の例なら、X -> (X -> Y) -> Y を基本部品としておいてそれをうまく組み合わせて [X] -> (X -> Y) -> Y を得る方法、というのを考えると思います。
#uriからsxml取ってくる関数とsxmlからデータを抜く関数からデータをとるので(U->S)->(S->[I])->[I]
#複数のsxmlのジェネレータをわたしてデータを抜いてくるので、[S]->(S->[I])->[I]
#ですね。
#それなら [S] ->(S -> [I]) -> [I] を基本関数にして U -> S の結果をシングルトンのジェネレータにしてつなげるっていうんじゃだめですか。
#つまり (U->S)->[S]ってアダプタを作ってつなげる、という意味です。
#なるほど。
#(U->S)->(S->[I])->(S->H)->(I->I)->(I->bool)-> ( H , [I] )
; (I->I) でアイテムの変換 (省略可、省略時はなにもしない)
; (I->bool)でフィルタする (省略可、省略時はなにもしない)
#という仕様なので、ヘッダ情報Hの扱いを別にする必要がありますね。
#U--(取得)-->S--(抽出)-->[I]--(変換)-->[I]--(フィルタ)-->[I] のフローと、U--(取得)-->S--(抽出)-->Hのフローがあって、それを合成したという感じの流れなんです。枝分かれして処理して、また合流するという流れです。