haskell-ja > Archives > 2011/09/13

2011/09/13 01:40:19 UTCkazu
#
すごい。やればできるじゃないですか! > chop
#
チュートリアルに採用させて頂きます。
#
tailDropWhile という高階関数にすると双対っぽくていいのかも。
2011/09/13 06:01:47 UTCkazu
#
コンビネータの例として名前を挙げたいものを募集します。
#
今のところ、パーサー、XML、SQ,
#
SQL、商取引、ハードウェア設計
#
が挙っています。
#
あと一つぐらい欲しいです。
#
(上の SQ, は誤植です。)
2011/09/13 06:18:47 UTCnobsun
#
図形言語?
#
プリティプリンタ
2011/09/13 06:31:40 UTCkazu
#
図形言語って、SICP のやつですか?
#
プリティプリンタはよさそうですね。
2011/09/13 07:12:34 UTCnobsun
#
そうです。Haskell版 > http://www.ipsj.or.jp/07editj/promenade/4610.pdf http://www.sampou.org/haskell/ipsj/#10
2011/09/13 07:47:34 UTCkazu
#
一応、チュートリアルの資料ができました。
#
http://www.mew.org/~kazu/kazu.pdf
#
意見を言って頂けると嬉しいです。
2011/09/13 08:31:27 UTCnobsun
#
tailDropWhile だと reverse . dropWhile isSpace . reverse より効率が悪るそう。
2011/09/13 08:36:56 UTCkazu
#
えーと、maoe さんの実装自体が効率が悪いという意味ですか? それとも、nobsun の chop とかは効率はいいが、tailDropWhile だけが効率が悪いという意味ですか?
2011/09/13 08:43:17 UTCnobsun
#
原因をうまく説明できないので曖昧ないいかだになりましたが、少くとも chop :: String -> String に関してはmaoeさんの実装も、私の実装も reverse .dropWhile isSpace . reverse よりも効率が悪いように思います。chopの実装にtailDropWhileを使うのはうまくないということです。
#
末尾空白が短く、全体が長い文字列で実験すると顕著にちがうように見えます。
2011/09/13 09:00:52 UTCnobsun
#
goの適用がリストのすべての要素上で評価されます。つまり go でのパターンマッチによる検査が毎回怒ることになりそれがネックになるのではないかと思います。
2011/09/13 09:02:28 UTCkazu
#
[] の部分を、ガードの null に変えてもダメでしょうか?
2011/09/13 09:06:44 UTCnobsun
#
もっと遅くなります。
2011/09/13 09:26:17 UTCkazu
#
どうやって計測してますか?
#
ああ、分かった。このコードは遅延評価と相性が悪い。
2011/09/13 09:29:18 UTCnobsun
#
ものすごくアバウト。ghci> :set +s
2011/09/13 09:29:19 UTCkazu
#
右側を計算し終わらないと、c : できないですね。
2011/09/13 09:29:42 UTCnobsun
#
そうです。
2011/09/13 09:29:43 UTCkazu
#
右側の計算結果が [] だったら、c : してはいけないから。
#
単純に x : f x とかだと、x : を忘れて f x を後で計算できます。
#
でも、このコードではダメですね。
2011/09/13 09:31:04 UTCnobsun
#
です。
2011/09/13 09:32:09 UTCkazu
#
では、reverse を使った tailDropWhile も示して、foldr バージョンは遅いとコメントに書くことにします。
2011/09/13 09:38:48 UTCkazu
#
書き換えておき直しました。> PDF
2011/09/13 15:05:26 UTC[1..100]>>=pen
#
import List; import Maybe; import Char

chop xs = catMaybes $ snd $ mapAccumR f True xs  where
  f endp x | isSpace x && endp = (True, Nothing)
           | otherwise         = (False, Just x)
2011/09/13 15:21:44 UTC[1..100]>>=pen
#
本質的に maoeさんのと同じか。
#
ただ isSpace を先にチェックした方がいいですよね。
2011/09/13 15:33:53 UTC[1..100]>>=pen
#
末尾空白が短く全体が長い文字列でも大丈夫じゃないかな。
2011/09/13 15:39:34 UTCnobsun
#
↑遅くないですか。sample = replicate (10^6) 'a' と定義しておいて length $ chop sample の計算時間を比べてみると遅さが判ります。
2011/09/13 15:43:31 UTC[1..100]>>=pen
#
うーーん、長い文字列の先頭数文字取るだけだったら速いかなと思ったんだけど。
#
あ、コンシューマーがいたら速いかなという意味でした。
#
全文字処理したらアドバンテージないですが。
2011/09/13 15:49:08 UTCnobsun
#
ああそうですねぇ。でも、tailDropWhile をわざわざやるということは、後ろがオチていることを見ることが大事になるわけだろうから。先頭数文字だけ使いたいという場合の方が少ないとおもうなぁ。
2011/09/13 15:50:45 UTC[1..100]>>=pen
#
全文字処理なら
#
take (fst . foldl' f (0,0) xs) xs
#
f (b,n) c | isSpace c = (b,n+1)
#
| otherwise = (n, n+1)
#
というのも考えたけどスピードどうだろう。
#
fst $
2011/09/13 15:57:11 UTCshelarcy@twitter
#
使い方によって変わる性能差をきちんとみたいなら、progression を使いましょう。 http://t.co/taQX9ge
2011/09/13 15:57:51 UTC[1..100]>>=pen
#
mapAccumR版は無限文字列にも対応してるぞ、ドヤッ。ということで。
#
しょせんぼくはトイプロブレムしかやりませんよ。いじいじ。
2011/09/13 16:02:01 UTCnobsun
#
勘違いしてました。その方が早いです。kazuさん:[] の部分を、ガードの null に変えてもダメでしょうか?
#
[1..100]>>=penさんの指摘どおり
#
tailDropWhile :: (a -> Bool) -> [a] -> [a]
tailDropWhile p = foldr go []
  where
    go c cs | p c && null cs = []
            | otherwise      = c:cs
2011/09/13 16:05:14 UTC[1..100]>>=pen
#
あ、mapAccumR 使わなくよかったのか。
2011/09/13 16:08:28 UTCnobsun
#
ただ、これでも reverse . dropWhile isSpace . reverse のほうが性能はいいようですねぇ。
2011/09/13 16:09:11 UTC[1..100]>>=pen
#
reverse の性能がいいんでしょうね。
2011/09/13 16:10:20 UTCnobsun
#
そうおもって、reverseとdropWhileを手で素朴に定義しなおしてます。
2011/09/13 16:10:50 UTCshelarcy@twitter
#
mapAccumR 版は foldr 版と違って、fold/build で融合変換できないので、与えるデータと最適化の有無で両者の性能は変わってきそうです。 http://j.mp/qWgQx1 http://j.mp/qzFBkW
2011/09/13 16:11:58 UTC[1..100]>>=pen
#
みんな探求精神旺盛でえらいなあ。
2011/09/13 16:12:52 UTCshelarcy@twitter
#
.。oO(まあ、最適化オプションを使わないのが前提なら、どうでも良い話ですが。)
2011/09/13 16:14:39 UTCnobsun
#
chop単独では融合変換とかは関係なさそうに思えるのですがそうではないのですか?
2011/09/13 16:15:49 UTC[1..100]>>=pen
#
hkothaさん(だっけ?)召喚せねば。
2011/09/13 16:17:52 UTCshelarcy@twitter
#
chop に与える String、chop が返す String が中間データ構造なので、これを排除するような融合変換が考えられますよね。
#
foldr や foldr を使って定義した関数を chop の定義に使えば、前者の chop に与える String を排除するような融合変換ができます。
#
で、確かに chop 単体では関係ないですけれど、実際に利用する場面を考えたら融合変換は重要だということです。
2011/09/13 16:22:14 UTCnobsun
#
はい。たとえば length $ chop s が最終目標ならそういうことなんですが。chop単独の性能についてはというつもりだったんです。
2011/09/13 16:23:50 UTC[1..100]>>=pen
#
やはり GHC とライブラリを読まんといかんな。
2011/09/13 16:28:42 UTCnobsun
#
でもって、tailDropWhileの意図は後ろを落としたリストを得ることなので、tailDropWhileをつかっておきながらdeforestationしたいという場面を想定するのが私には難しいです。
2011/09/13 16:28:53 UTCshelarcy@twitter
#
私は、chop の性能を言う場合に chop 単体の性能を言って意味があるのか、実際に利用されるケースについて考えないといけないのではないか、というところに引っかかりを覚えました。
2011/09/13 16:32:07 UTCnobsun
#
そんなことはないか。deforestationしたことはいくらでもあるな。
#
した→したい
2011/09/13 16:36:22 UTC[1..100]>>=pen
#
まあ、人間普段の活動で100mだけ走ることはないけどオリンピックの100m競争はそれはそれで意味あるからなあ。両ケースでの効率わかるといいですね。
2011/09/13 16:36:24 UTCshelarcy@twitter
#
遅延評価で呼ばれる度にリストの次の要素を作成する関数と、tailDropWhile、この二つの間に発生するリストを排除したくなっても良いですよね?
2011/09/13 16:37:23 UTCnobsun
#
一番簡単なれいはまさに length $ chop s ですよね。
2011/09/13 16:39:28 UTC[1..100]>>=pen
#
reverseとdropWhile手作りバージョン楽しみです。
2011/09/13 16:40:12 UTCnobsun
#
え?何を期待してます?↑
2011/09/13 16:41:29 UTC[1..100]>>=pen
#
スピードがどうなるか。もう結果でました?手作り版でも reverse版の方が速いということですか?
#
そうだとしたら関数コールのスタック使うのが遅い原因かもということか。
2011/09/13 16:45:30 UTCnobsun
#
いやそもそもghciでのいい加減な比較だから :p
#
当然コンパイル済みのコードかそうでないかの性能差がでる。
2011/09/13 16:47:26 UTC[1..100]>>=pen
#
な、な、なんだってー! ghci!
2011/09/13 16:47:50 UTCnobsun
#
だから手作りしたんだってば。
2011/09/13 16:52:07 UTCnobsun
#
reverse版が速いのは分岐判断の数が少ないからだとおもう。つまり分岐判断処理が重いってこと
2011/09/13 16:54:24 UTC[1..100]>>=pen
#
でも分岐は dropWhile で同じことしてるでしょ。
#
あ、違うか。
#
理解しますた。
#
深いなあ。
#
じゃあ、foldr(foldlじゃなくて) で長さだけ先に計算させて take するのはどうでしょう。
2011/09/13 17:01:18 UTCnobsun
#
やってみそらしど。reverse版と
#
おなじ構造になるから。
2011/09/13 17:02:08 UTC[1..100]>>=pen
#
逆文字列つくらない分軽そうな気がするんだけど。
2011/09/13 17:02:47 UTCnobsun
#
やってみそらしど。
2011/09/13 17:03:27 UTC[1..100]>>=pen
#
やらないね(他人(ひと)まかせ)
#
どちらも関数コールがスタックにたまってるから同じなのかな。
2011/09/13 17:05:49 UTCnobsun
#
かずかぞえるのにけっきょくさいごまでリストたどるでしょ?
2011/09/13 17:06:30 UTC[1..100]>>=pen
#
全部なめるのはしょうがないのはOK。
2011/09/13 17:07:03 UTCnobsun
#
ああさっきのコードですか?
2011/09/13 17:07:43 UTC[1..100]>>=pen
#
長さだけ計算すると途中に作る構造が少なくてすむかなあああと。
#
foldr版の話。
2011/09/13 17:09:17 UTCnobsun
#
メモリはせつやくできるけど、述語適用がやっぱり要素分だけひつようになるんじゃない?
2011/09/13 17:10:30 UTC[1..100]>>=pen
#
一回の適用が軽くならないかなあああという願望。
2011/09/13 17:15:42 UTCnobsun
#
なんないと思うなぁ。
2011/09/13 17:16:33 UTC[1..100]>>=pen
#
そうかい、そうかい。明日自分でやってみるよ。プンプン。
2011/09/13 17:16:49 UTCnobsun
#
まぁちょいまちねぇ。
2011/09/13 17:17:07 UTC[1..100]>>=pen
#
なにか面白いネタが残ってますか。
2011/09/13 17:18:00 UTCnobsun
#
竹のこーどかいてみるから。
2011/09/13 17:18:50 UTC[1..100]>>=pen
#
wktk
#
竹とdろp。
2011/09/13 17:27:19 UTCnobsun
#
あかん。おそすぎ
2011/09/13 17:27:33 UTC[1..100]>>=pen
#
orz
#
寝ます。
2011/09/13 17:28:31 UTCnobsun
#
replicate (10^7) 'a' くわせたら帰ってこん。
2011/09/13 17:28:31 UTC[1..100]>>=pen
#
とても勉強になりました。
#
みんなありがとう。月が綺麗ですね。
2011/09/13 17:29:13 UTCnobsun
#
ありや、おぬしのコードまちごうとるぞ
2011/09/13 17:29:36 UTC[1..100]>>=pen
#
おぬしって誰。
2011/09/13 17:29:53 UTCnobsun
#
そこのおぬじゃ。
#
あれ。
#
わしか?
2011/09/13 17:30:28 UTC[1..100]>>=pen
#
foldどっち版?
2011/09/13 17:30:59 UTCnobsun
#
chop' s = take (fst $ foldl' f (0,0) s) s
  where f (b,n) c | isSpace c = (b,n+1)
                  | otherwise = (n,n+1)
#
であってる?
2011/09/13 17:31:33 UTC[1..100]>>=pen
#
foldlじゃない方で、って書いたでしょう。
2011/09/13 17:32:28 UTCnobsun
#
コードかいて?
2011/09/13 17:32:37 UTC[1..100]>>=pen
#
foldr で末尾から計算した版をつくって欲しい。
#
今日は私はもう書かない。
2011/09/13 17:33:27 UTCnobsun
#
ちょいまて。
2011/09/13 17:33:39 UTC[1..100]>>=pen
#
待ちましょう。
#
zip [1..
#
zip [1..] したのと直接カウントアップするのではどちらが速いかな。
2011/09/13 17:36:34 UTCnobsun
#
chop' s = take len s
  where
    len = foldr f 0 s
    f c n | isSpace c && n==0 = 0
          | otherwise         = n+1
#
でいいかい?
2011/09/13 17:37:36 UTC[1..100]>>=pen
#
ゆっくり確認しますのでそれで試してみてください。
2011/09/13 17:39:06 UTCnobsun
#
これスタックふくれまくりだとおもうけど。。。
2011/09/13 17:39:40 UTC[1..100]>>=pen
#
どっかで seq でいないかな。
2011/09/13 17:40:06 UTCnobsun
#
そらむり。foldl'じゃないと
2011/09/13 17:40:31 UTC[1..100]>>=pen
#
あ、関数コールスタックはしょうがないか。
2011/09/13 17:40:41 UTCnobsun
#
まつびさいきでないとだめでしょ。
2011/09/13 17:41:32 UTC[1..100]>>=pen
#
ともかくやってみてください。すでにテスト中かな。
2011/09/13 17:43:05 UTCnobsun
#
かえってこないので、データちいさくするね。
#
*Main> length $ chop sample
1000000
(0.11 secs, 54012312 bytes)
*Main> length $ chop' sample
1000000
(4.46 secs, 261028772 bytes)
2011/09/13 17:44:10 UTC[1..100]>>=pen
#
| isSpace c = n
#
みたくしたいな。
#
n を1ずらしたらできないかな。
#
って、そんな小細工したくらいじゃ追いつかない差?
2011/09/13 17:46:03 UTCnobsun
#
そう。
#
foldl' 版の方がましじゃない?
2011/09/13 17:47:09 UTC[1..100]>>=pen
#
orz。
#
この版は一往復半するからなあ。
2011/09/13 17:48:12 UTCnobsun
#
だって、どうせ長さかぞえるなら、foldl' じゃない?
#
でもコードがびみょうにちがうんだな。
2011/09/13 17:48:37 UTC[1..100]>>=pen
#
だって条件分岐が効くからって言うからー
#
2011/09/13 17:48:42 UTCnobsun
#
1ずれてる > foldl'
#
だからfoldr版条件分岐へってないじゃん。
2011/09/13 17:49:51 UTC[1..100]>>=pen
#
興味が出てきたので明日考え直してみます。
#
いや、長さの計算のときに減ってるはず。
2011/09/13 17:50:20 UTCnobsun
#
なんで?
2011/09/13 17:50:34 UTC[1..100]>>=pen
#
| otherwise = n+1
#
で c を使ってない。
#
え、勘違いしてる?
#
してるような気がしてきた。
2011/09/13 17:51:33 UTCnobsun
#
さっきの
#
tailDropWhile :: (a -> Bool) -> [a] -> [a]
tailDropWhile p = foldr go []
  where
    go c cs | p c && null cs = []
            | otherwise      = c:cs
#
だって使ってなくね。
2011/09/13 17:52:32 UTC[1..100]>>=pen
#
isSpace でスペースでなければ直帰するつもりでいたけど
#
してないようなきがしてきた。
#
and/or が途中で直帰できるのはなんでだっけ。
2011/09/13 17:53:22 UTCnobsun
#
してまへんがな。第二引数について正格だから直帰できない。
2011/09/13 17:53:40 UTC[1..100]>>=pen
#
あ、そうだ。
2011/09/13 17:53:45 UTCnobsun
#
第二引数について正格でなくてもよいことがあるから。
2011/09/13 17:53:57 UTC[1..100]>>=pen
#
zip [1..] 版ならどうだ!
2011/09/13 17:54:19 UTCnobsun
#
おんなじじゃね。
2011/09/13 17:54:39 UTC[1..100]>>=pen
#
今度は直帰できるでしょうがー!
2011/09/13 17:54:49 UTCnobsun
#
どうやって?
2011/09/13 17:55:18 UTC[1..100]>>=pen
#
あれ、どうだっけ。
2011/09/13 17:55:35 UTCnobsun
#
うしろまでみなくちゃいけないことにはかわりないでしょうが。
#
だからちょっきできない。
2011/09/13 17:56:04 UTC[1..100]>>=pen
#
foldr なんかやめて再起にしろー!
2011/09/13 17:56:26 UTCnobsun
#
おんなじじゃっちゅうとろうが。
2011/09/13 17:56:28 UTC[1..100]>>=pen
#
再帰だった。orz
#
いや、再帰なら直帰できる。
2011/09/13 17:56:47 UTCnobsun
#
できまへんて
2011/09/13 17:57:12 UTC[1..100]>>=pen
#
いや、できるね。(根拠なし)
2011/09/13 17:57:15 UTCnobsun
#
さいごまでみなきゃいけないのはchopの本質!!!
2011/09/13 17:57:38 UTC[1..100]>>=pen
#
foldr の帰りの途中で直帰できるのでは。
#
あっ。
#
foldr は順番いかえっていくのですね。orz
#
callCC の出番か。
#
もやは敗北状態。
2011/09/13 18:01:02 UTCnobsun
#
ちょっきできるようにするためにはまえからたどったときにそれをちくせきしておく必要がある。でも蓄積は逆順になるから、reverseが必要になる
2011/09/13 18:02:39 UTC[1..100]>>=pen
#
継続的なことすればなんかできような気がしてきた。(根拠なし)
2011/09/13 18:02:45 UTCnobsun
#
けっきょく最低1往復必要
2011/09/13 18:02:47 UTC[1..100]>>=pen
#
明日で勘弁してください。
2011/09/13 18:02:56 UTCnobsun
#
ならん!
2011/09/13 18:02:57 UTC[1..100]>>=pen
#
1往復が必要なのはOK.
#
あ、そう言ってないか。
#
直帰できるって言ったな。
2011/09/13 18:04:29 UTCnobsun
#
ちょっきできるけど、先につんだものをreverseするから、1往復と同じ
2011/09/13 18:04:41 UTC[1..100]>>=pen
#
コンパイルエラー全部記録しますから今日は勘弁してください。
2011/09/13 18:05:44 UTCnobsun
#
きょうのところは勘弁してやろう :p これきりだぞ :)
2011/09/13 18:06:05 UTC[1..100]>>=pen
#
ありがとうごぜーます。
2011/09/13 18:06:17 UTCnobsun
#
うむ。おやすみ。
#
:)
2011/09/13 18:08:03 UTC[1..100]>>=pen
#
「コンパイルエラーの年貢は全部納めますから」と書くべきだった。
2011/09/13 19:07:00 UTC[1..100]>>=pen
#
寝る前にメモ。
#
・reverseには不利であろうすべて空白文字列での比較。
#
・本当に直帰する catch try を使ったら。
#
寝る。
2011/09/13 23:07:17 UTCnobsun
#
すべてくうはくはreverse版に不利にはならない
#
ちょっきするときに持って帰るものをどうやってつくるのかが問題
#
融合変換の可能性があるというが本当か?それが欲しい具体的例題はなにか?foldr版tailDropWhileの使い道は本当にあるのか?
#
あたりが課題だろうけど、感覚的にはNOだとおもうなぁ。
2011/09/13 23:46:21 UTCnobsun
#
とおもったけど。こんな例題ならどうだろう
2011/09/13 23:50:38 UTCnobsun
#
テキストデータの80桁を超える部分を切り捨て、末尾の空白も切り捨てたい
#
末尾→行末
#
ああこの例題よくないなぁ