文字列をリストで与えられた長さに区切る

例えば Ruby で書くとこういうやつ。

takatoh@nightschool $ ruby split_with.rb
["a", "bc", "def", "ghij"]

Scheme ではどうだろう。

フツウの再帰版

なんの工夫もない。

takatoh@nightschool $ gosh split-with.scm
(a bc def ghij)

末尾再帰版

ちょっと工夫して末尾再帰。

takatoh@nightschool $ gosh split-with2.scm
(a bc def ghij)

map-accum版

もう少し何かないかと探したら、map-accum があった。

これはちょっと説明をしておく。split-with の中で let を使って手続き f を定義している。これは、リストの各要素に適用される手続きで、2つの引数をとって 2つの値を返す。多値ってやつだな。覚えてるぞ。values で2つの値を返せばいい。1つ目は map の様に集められて、もう1つは次の適用の引数になる。で、map-accum 自体も2つの値を返す。1つ目は f の1つ目の返り値を集めたリストで、もう1つは最後の適用の2つ目の返り値だ。値が2つ返ってくるので、receive を使って l と s で受けている。s の方は使ってないけどね。最後に、l は文字のリストのリストになているので、文字列のリストに変換して完了。

takatoh@nightschool $ gosh split-with3.scm
(a bc def ghij)

実行時間の比較

せっかくなので比較してみた。

takatoh@nightschool $ time gosh split-with.scm
(a bc def ghij)

real	0m0.012s
user	0m0.011s
sys	0m0.000s
takatoh@nightschool $ time gosh split-with2.scm
(a bc def ghij)

real	0m0.015s
user	0m0.009s
sys	0m0.005s
takatoh@nightschool $ time gosh split-with3.scm
(a bc def ghij)

real	0m0.023s
user	0m0.023s
sys	0m0.000s

再帰版と末尾再帰版はあんまり変わらないけど、map-accum 版は明らかに遅い。そういうもんか。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です