星田さんの記事に対するコメント。
はぁ~・・可変長引数!なるほど~。リストとしてまとめられるのでapplyが使えるって事なんですな?
そういう事、です。
これ、2つを組み合わせたら行けるだろうな~とは思ってたんですけどこんなにシンプルに出来るとは!今まで出くわさなかったけどdefineで述語を作るときってこういう感じになるんですね。なんかcondで場合分けをして・・とか考えてたけど述語自体を作ってしまえば良いとは~・・カンニングして助かった(^_^;)
結局、述語は#tか#fしか返さないんで、ifとかcondを使うと大仰しいんですよ。
それより、andとかorとかnotを上手い具合組み合わせて要求される結果を出した方がbetterです。その辺の考え方はPythonでも使えます。
んで、暗記する必要はないんだけど、場合によっては論理演算を使うとスマートに書ける確率が高くなる。
うん、暗記する必要はない。Wikipediaによるアンチョコ案件です(笑)。
各文字列に適用する順序は不定!?ここでの違和感が伏線だったか・・
これはねぇ・・・・・・。うーん、覚えてた方がいいけど、半分くらいは実装者向け情報かなぁ・・・・・・。
つまり、最適化の問題があるわけですよ。string-mapは文字列版のmap、で殆どのケースでは、使用者はその辺意識せんで良い。
でも仮に、call/ccなんかでstring-mapから脱出した場合、「計算が終わった部分の文字列」は僕らが期待したモノになってない可能性がある、って事です。
例えば。直球勝負でstring-mapを書くと次のようになるでしょう。
(define (string-map proc . s)
(list->string (map proc (apply string->list s))))
これはこれでイイ。文字列から生成されたリストを順序よく処理していって結果を出す。
> (string-map (lambda (x)
(if (char-numeric? x)
#\e
x)) "I'm a l33t hack3r")
"I'm a leet hacker"
ただ、データ変換を都合二回行ってるので、非効率だ、ってツッコまれればその通りですよね。
「多用されるライブラリを作る」場合、内部的には効率優先で、もっと生臭いコードを書く場合がある。得られる結果が同じでもスピード優先で「優雅なコード」にならない場合がある、って事です。そしてそのテの「最適化」は実装者の裁量に任されるわけですよ。
それによるとstring-mapは「破壊的変更を辞さない」コーディングとして載っている。
(define (string-map proc s . maybe-start+end)
(check-arg procedure? proc string-map)
(let-string-start+end (start end) string-map s maybe-start+end
(%string-map proc s start end)))
(define (%string-map proc s start end) ; Internal utility
(let* ((len (- end start))
(ans (make-string len)))
(do ((i (- end 1) (- i 1))
(j (- len 1) (- j 1)))
((< j 0))
(string-set! ans j (proc (string-ref s i))))
ans))
これ、見たら分かるけど、思いっきり破壊的変更してますね(笑)。しかも文字列を逆順に生成していってる。
でも結果は関数型で得られる結果なんです。このように関数型プログラミングではユーザーは関数プログラミングしてますが、内部がそのように動いてるかどうか、ってのは保証外なんです。
全部が全部優雅なプログラミングだとさすがに効率が悪いんで、人の目の付かないトコではどーなってるか分からん、って事なんですよ(笑)。
少なくとも、こういうカンジで、文書で仕様が纏められてて、「手続き proc を文字列 s の各文字に適用する順序は不定である」って書かれてるのは実装者側にとってはある種福音なんです。「効率化の為に、直球勝負を避けて、好きに最適化してもいいですよ」と言う保証になるからです。
計算過程はどうでもいい、計算結果が大事だ、と宣言されたに等しいわけですから。
そういう事はしばしば起こり得るのです・・・・・・実装者側は大変だよなぁ(笑)。
偽の場合のsに違和感。え・・?ひょっとしてmap系の作用のイメージを全く勘違いしてたのでは・・。
いや、勘違いしてないでしょう。コードの読み方にちと誤解があるだけ、で。
(lambda (x) ; 文字列から x を取り出して
(if (pred? x) ; pred?が真を返したら
newitem ; x を newitem で置き換える
x)) ; 偽なら x のまま
ですね。
newitemとxを並べて書いたから勘違いしちゃったのかな。多分。