1 名前:デフォルトの名無しさん mailto:sage [2012/01/02(月) 22:19:28.26 ] haskell.org ttp://www.haskell.org/ 日本語サイト ttp://www.sampou.org/cgi-bin/haskell.cgi ttp://www.shido.info/hs/ 過去ログ 関数型プログラミング言語Haskell Part1 ttp://pc.2ch.net/tech/kako/996/996131288.html Part2 ttp://pc2.2ch.net/test/read.cgi/tech/1013846140/ Part3 ttp://pc8.2ch.net/test/read.cgi/tech/1076418993/ Part4 ttp://pc8.2ch.net/test/read.cgi/tech/1140717775/ Part5 ttp://pc8.2ch.net/test/read.cgi/tech/1149263630/ Part6 ttp://pc11.2ch.net/test/read.cgi/tech/1162902266/ Part7 ttp://pc11.2ch.net/test/read.cgi/tech/1174211797/ Part8 ttp://pc11.2ch.net/test/read.cgi/tech/1193743693/ Part9 ttp://pc11.2ch.net/test/read.cgi/tech/1211010089/ Part10 ttp://pc12.2ch.net/test/read.cgi/tech/1231861873/ Part11 ttp://pc12.2ch.net/test/read.cgi/tech/1252382593/ Part12 ttp://hibari.2ch.net/test/read.cgi/tech/1272536128/ Part13 ttp://hibari.2ch.net/test/read.cgi/tech/1286706874/ Part14 ttp://hibari.2ch.net/test/read.cgi/tech/1299385928/ Part15 ttp://hibari.2ch.net/test/read.cgi/tech/1310199414/ Part16 ttp://toro.2ch.net/test/read.cgi/tech/1317958045/
338 名前:デフォルトの名無しさん mailto:sage [2012/01/23(月) 21:30:27.63 ] >>309 イテレーティ解説サイト教えてください!(日本語の)
339 名前:デフォルトの名無しさん mailto:sage [2012/01/23(月) 21:30:48.60 ] >>337 だからさ、お前が「〜みたいな」って自分で言ってるじゃん その抽象的な「みたいな」をもっと具体的に説明してくれよ じゃないと、それが >>333 の喩えにちゃんとなっているのか、 あるいは >>334 が勝手に喩えていると勘違いしてるだけで、 何も喩えられていないのか、判断に困るだろ
340 名前:デフォルトの名無しさん mailto:sage [2012/01/23(月) 21:35:22.98 ] >>338 「iteratee haskell」で日本語サイトをググってみたか? たとえば d.hatena.ne.jp/mkotha/20111106/1320584724 こんなページがヒットしたんだが >>337 「具体化できない奴がやたら抽象化にこだわる」事がどういう事か、 自分でもあまりよく分かって(頭の中で整理できて)ないんだろ? だから、例えばこういう奴とか言って具体例が出てこないんだろ?
341 名前:デフォルトの名無しさん mailto:sage [2012/01/23(月) 21:48:59.93 ] 抽象化にこだわってるかどうかは知らんが、 とにかく具体的なコード書く能力が無いのは事実だな 「シーク禁止じゃなければ速いtail書けるんだけど、でも泥臭くなるから……(ぶつぶつ」 とか言いながら実際にはシーク使ったコードは書けない、みたいな
342 名前:デフォルトの名無しさん mailto:sage [2012/01/23(月) 21:55:46.74 ] case of で、あるマッチングと別のマッチングで全く同じ式を計算させたい場合、 どう式を書くのがより合理的なのでしょうか 例えば次のような感じです data T = A Char | B Bool | C Bool | D Int | E String f :: T -> Int f x = case x of A d -> g1 d B d -> g2 d C d -> g2 d otherwise -> 0 パターン B b とパターン C d の場合が同じ式になっています この例の場合、レスの文字数などの関係で g2 d というように関数を適用してますが、 実際は別の関数にするほどでもなく、それでいて短くもないような、 例えば let が2〜3行に in が1行程度の式だったりします 2つのパターンの場合に同じ式を計算する事を分かりやすく示したいのですが、 C言語の switch case のフォールスルーみたいには書けないですよね コピペのミスなどを防ぐには、この例のように関数にまとめて、 それを呼ぶだけの式にするくらいしか手はないでしょうか
343 名前:デフォルトの名無しさん [2012/01/23(月) 22:00:11.07 ] >>339 具体化=泥臭い=hSeekでシコシコ読み込む方法と、すでに出ていることから察するに、 恐らく>>333 へ文句言ってると受け取って、こっちの文意が伝わってないのかなと思った でも>>339 では喩えになっているかって言ってるもんな 何かトンデモないこと言ってしまったんだろうか たしかに>>334 は毒づきすぎたから、そこはごめんなさい 議論の邪魔して失礼しました
344 名前:デフォルトの名無しさん mailto:sage [2012/01/23(月) 22:13:40.06 ] 誰かhSeek でスマートに実装したtailください
345 名前:デフォルトの名無しさん mailto:sage [2012/01/24(火) 07:56:12.73 ] >>333 言いたいことは分かるが、ある程度は仕方がない 数回経験すれば自然と分かることだが、 Haskellで泥臭くやると、C言語などで泥臭くやる場合以上に 面倒で、スパゲッティで分かりにくくなり、かつメンテが難しくなる Haskellで泥臭くやるということは、手続き的な、 つまり計算「順序」に過剰に縛られたプログラムを書くということ 順序に縛られているから計算が一本の長い紐になり、 それがソース上の関数群を複雑に縫い止める C言語などなら、そこから少しずつリファクタリングし、処理単位の小さくし、 縫い合わされた巨大な処理を細かくばらすことは良くある でもHaskellでは一度複雑に縫い止めた関数群を少しずつばらすのは容易ではない 計算順序を意識しすぎた為にそうなったのであり、その意識を変えなければ無理 考え方そのものを変えた場合、少しずつ修正するよりは全てやり直した方が早い そうすると、後で全てやり直すくらいなら、初めから意識を変えて、 計算順序に過剰に縛られないように作ることに意識が向くようになる 初心者のうちは「意識を変えなければならない」という事が面倒でたまらないが、 そのうち「わざわざ」泥臭いことをやってはいけないという意識は消えていく 自然と泥臭いことをしなくなる
346 名前:デフォルトの名無しさん mailto:sage [2012/01/24(火) 11:09:18.39 ] >>345 333じゃないけど、それは自分の実感と全然違うな Haskellで手続き的なコードを書くのは良くやるけど、 Cでやるのに比べて面倒だと思うことはほとんどない 多次元のmutable配列とかがHaskellだと構文的にごちゃごちゃするくらい リファクタリングについては、なんでそんな結論に至ったのか理解に苦しむ 局所関数定義と高階関数を自在に使える時点でCとは比較にならない そもそも「計算順序を意識」するのを止めるだけで関数的に綺麗なアルゴリズムが出てくる訳でもない 時間O(1)のtailを実装するには結局seekするしかないんだよ
347 名前:デフォルトの名無しさん mailto:sage [2012/01/24(火) 12:11:52.41 ] だれかHaskellのスパゲティ屋さんのプログラム見せて
348 名前:デフォルトの名無しさん mailto:sage [2012/01/24(火) 12:33:17.39 ] >>347 >>46
349 名前:デフォルトの名無しさん mailto:sage [2012/01/24(火) 12:34:10.82 ] >>346 「計算順序を意識」とは言っていない 「計算順序を意識しすぎる」や「計算順序に過剰に縛られた」と言っている 意識しなければ正しい計算ができない事は承知している
350 名前:349 mailto:sage [2012/01/24(火) 12:49:06.27 ] それと > 時間O(1)のtailを実装するには結局seekするしかないんだよ 分かっている だから私はtailの時間O(1)の実装には一言も触れていない >>345 では、わざわざ泥臭いことをやってはいけないという空気になりがちな 私なりの理由を述べた(tailの実装といった具体的な対象ではなく一般論) やってはいけないとは言いすぎだと思うが、アプリの設計開始時から、 または Haskell によるプログラム開始時から 泥臭いことをやってはいけないというくらいの考えでプログラムした方がいいと思う 少なくとも Haskell では 泥臭い事を考えるのは、そうしなければ目標を達成する術が残っていない場合だけ 本当に最後の最後に考える最終手段くらいのもの 本来はもっと抽象度を高める方向に意識を向けた方が良いと思う 例えば seek で1バイトずつ取得したものを文字と解釈して計算するよりも、 getContentsに任せて「ファイルの内容を計算対象にする」方が抽象度は高い 蛇足かも知れんが、ついでに言えば入門書も抽象度を高める考え方や方法を伝授すべきだと思う
351 名前:デフォルトの名無しさん mailto:sage [2012/01/24(火) 14:10:06.15 ] >>350 お前がそういう意見なのは全然構わん >>345 が「Haskellは泥臭いことをやるのには向かない」と 言っているように読めたので反論しただけ 個人的には泥臭いのを嫌がっていては実用コードは書けないと思っているから
352 名前:デフォルトの名無しさん mailto:sage [2012/01/24(火) 15:21:05.01 ] >>348 TX クラクラ来た。
353 名前:デフォルトの名無しさん mailto:sage [2012/01/24(火) 15:36:49.63 ] >>350 >本当に最後の最後に考える最終手段くらいのもの 最初でも最後でもどっちでもいいんじゃないの なぜ順序を決めたがるのか
354 名前:デフォルトの名無しさん mailto:sage [2012/01/24(火) 16:01:49.74 ] >>340 あざっす^^
355 名前:デフォルトの名無しさん mailto:sage [2012/01/24(火) 19:15:01.19 ] >>353 俺は >>350 じゃないので横レスになるが、決める決めないじゃなくて、言語の文化としてより自然なやり方はあると思う。 例えて言うなら、日本語は格助詞があるから語順はある程度自由なはずだが、やっぱり自然な語順はあるだろ。 そんな感じ。 やりたい奴はもちろん最初っから泥臭く書いたってそりゃかまわないが、 たいした理由もないのにあえて泥臭く書くのでは Haskell を使う甲斐が無い。
356 名前:デフォルトの名無しさん mailto:sage [2012/01/24(火) 20:34:12.21 ] つまりムダなIO発生させていい気になってるってことねw トイならそれでもいいけど実用でそれやったらアホだぞ どれだけキャッシュの無駄遣いすると思ってんだか
357 名前:デフォルトの名無しさん mailto:sage [2012/01/24(火) 20:55:06.07 ] 別に抽象度高めつつ、無駄なキャッシュも減らすようにできると思うんだが、 どっちもどっちだな〜。 どっちもあほ。
358 名前:デフォルトの名無しさん mailto:sage [2012/01/24(火) 21:08:23.56 ] >>357 (ふりだしにもどる) 数GBあるログをtailするコードをHaskellで書いてみてくれ
359 名前:デフォルトの名無しさん mailto:sage [2012/01/24(火) 21:09:07.58 ] とりあえず叩き台としてコード書いてみたよ。 tailFile n h = do seekable <- hIsSeekable h if seekable then do sz <- hFileSize h hSeek h AbsoluteSeek $ max 0 (sz - n) hGetContents h else do takeLast n <$> hGetContents h takeLast n xs = diff xs (genericDrop n xs) where diff xs [] = xs diff (_:xs) (_:ys) = diff xs ys
360 名前: [―{}@{}@{}-] デフォルトの名無しさん mailto:sage [2012/01/24(火) 22:17:01.53 ] d.hatena.ne.jp/slayer845/20120123/1327328227 性能は出ているらしい conduit読めないから俺にはいまいち何やってるか分からんが
361 名前:デフォルトの名無しさん mailto:sage [2012/01/24(火) 23:33:17.89 ] 批判組早く
362 名前:デフォルトの名無しさん mailto:sage [2012/01/24(火) 23:42:03.26 ] 手続き型の言語による実装と抽象度では大差ないか劣るのではないか
363 名前:デフォルトの名無しさん mailto:sage [2012/01/24(火) 23:43:15.57 ] >>359 行数指定できないから0点
364 名前:デフォルトの名無しさん mailto:sage [2012/01/24(火) 23:55:11.19 ] 晒した勇気に100点をあげたい。
365 名前:デフォルトの名無しさん mailto:sage [2012/01/24(火) 23:58:01.89 ] 間とって50点
366 名前:デフォルトの名無しさん mailto:sage [2012/01/25(水) 00:21:24.87 ] 相乗平均なら0
367 名前:デフォルトの名無しさん mailto:sage [2012/01/25(水) 01:31:32.52 ] 行数指定時用のコードを書いみたよ。 なんとなく遅延IO使ってみたよ。Iteratee使えるならそっちの方がいいんじゃないかな。 hGetLinesReversed :: Handle -> IO [String] hGetLinesReversed h = hFileSize h >>= lazyLoop h [] where lazyLoop h rest pos = unsafeInterleaveIO $ loop h rest pos loop h rest pos | pos < 0 = return [rest] | otherwise = do hSeek h AbsoluteSeek (max (pos-blockSize) 0) xs <- replicateM (fromInteger (min blockSize pos)) (hGetChar h) let (hd:tl) = lines (xs++rest) (reverse tl ++) <$> lazyLoop h hd (pos - blockSize) blockSize = 128
368 名前:デフォルトの名無しさん [2012/01/25(水) 02:10:21.02 ] 遅延IOとな 結局unsafe使う以外に方法って見つかってないんだよね?
369 名前:デフォルトの名無しさん mailto:sage [2012/01/25(水) 04:13:13.51 ] 普通の getContents とかも遅延IOだけど……
370 名前:デフォルトの名無しさん mailto:sage [2012/01/25(水) 06:30:19.08 ] >367 これを使ってO(1)のtailを作れたら神だな。
371 名前:デフォルトの名無しさん mailto:sage [2012/01/25(水) 07:24:35.01 ] >>368 は >>367 が unsafe 系を使ってる理由を 「処理速度を出す為」だと思ってるんじゃないだろうか
372 名前:デフォルトの名無しさん mailto:sage [2012/01/25(水) 07:57:17.27 ] >>370 普通に書けばファイルサイズに対してO(1)時間になるんじゃね?
373 名前:デフォルトの名無しさん mailto:sage [2012/01/25(水) 21:53:21.47 ] unsafe使わずに書いてみた。 ファイルサイズチェックしてないので、10行無かったり、小さすぎるのは駄目だけどね。 main = do h <- openFile "test.log" ReadMode hGetLinesTail h 10 0 >>= putStrLn hClose h blockSize = 128 hGetLinesTail h l pos = do xs <- hGetContentsSeekFromEnd h pos if l > (length$lines xs) then hGetLinesTail h l (pos + blockSize) else return xs hGetContentsSeekFromEnd h pos = do hSeek h SeekFromEnd (-pos) replicateM (fromInteger pos) (hGetChar h)
374 名前:デフォルトの名無しさん mailto:sage [2012/01/25(水) 21:58:39.36 ] すまん。インデントがずれてしまった、、、 main = do h <- openFile "test.log" ReadMode hGetLinesTail h 10 0 >>= putStrLn hClose h blockSize = 128 hGetLinesTail h l pos = do xs <- hGetContentsSeekFromEnd h pos if l > (length$lines xs) then hGetLinesTail h l (pos + blockSize) else return xs hGetContentsSeekFromEnd h pos = do hSeek h SeekFromEnd (-pos) replicateM (fromInteger pos) (hGetChar h)
375 名前:デフォルトの名無しさん mailto:sage [2012/01/26(木) 15:33:16.32 ] その言語の背景にあるパラダイムを上手に活用できればスマートな プログラムになるだろうけど、 強引に別のパラダイムのものに合わせようとすると悲惨になるのは当然じゃろ? そのパラダイムに応じた方法を模索していくしかないような。 Haskellって他よりパラダイムが明確なだけに得手不得手があるのは 仕方がなさそうよね。
376 名前:デフォルトの名無しさん mailto:sage [2012/01/26(木) 16:55:41.77 ] Unixコマンドは標準入出力をストリームとして扱う点で 関数型言語のパラダイムと親和性があると思うけどな Broken Pipe
377 名前:デフォルトの名無しさん mailto:sage [2012/01/26(木) 17:41:23.30 ] >>375 結局、メタパラダイムとかいうのは的外れってことだね
378 名前: [―{}@{}@{}-] デフォルトの名無しさん mailto:sage [2012/01/26(木) 19:26:22.04 ] Haskellは関数型+手続き型なのでそんなに極端な得手不得手はない
379 名前:デフォルトの名無しさん mailto:sage [2012/01/26(木) 20:04:34.51 ] そんなに極端な得手不得手はないが、悲惨なことになるのか...
380 名前:デフォルトの名無しさん mailto:sage [2012/01/26(木) 20:23:58.12 ] >>376 標準入出力をストリームとして扱うのはインターフェースの部分 内部では tail が代表するように単純にストリームでは扱っていない 関数型は無限リストや継続などでストリームを上手く表現できるが、 今回話題になっている話はインターフェースじゃなくて内部処理の方 正方向で流れてくる情報を逆方向からたどるというのは、 ある意味ストリームとは対極にある処理だと思う 内部処理もストリームにする事に拘るなら、 逆方向にする時にバッファにため込む必要がある (たまたま Haskell では遅延評価のおかげでそのバッファ処理を自動化できるが)
381 名前:デフォルトの名無しさん mailto:sage [2012/01/26(木) 20:33:13.40 ] 正格評価でもバッファぐらい普通にできるが?
382 名前:デフォルトの名無しさん mailto:sage [2012/01/26(木) 20:43:46.18 ] >>381 正格評価ではバッファを普通にはできない、 と言っているように感じたのか それなら申し訳ない 遅延評価という仕組みを実現するためのGHCの実装のおかげで、 バッファを作らなきゃいけないことを意識する必要がない という意味で言ったのだ 念のために言い添えておくと、処理速度などの話とは全く別のことだ
383 名前:デフォルトの名無しさん mailto:sage [2012/01/26(木) 21:37:21.78 ] 遅延評価とバッファの関係がよくわからないな。 少なくとも>374のコードは再帰するたびに毎回ファイル末尾から読み直してるようにみえる。 行のサイズ = blockSizeのファイルに対して、 tail nを計算するのにO(n^2)の処理を行っているのでは?
384 名前:デフォルトの名無しさん mailto:sage [2012/01/26(木) 22:05:50.63 ] >>383 > 遅延評価とバッファの関係がよくわからないな。 >>374 のコードは今回の私の話とは全く関係ない >>376 のストリームの話だ 逆順に指定行数を出力するという処理を「ストリームとして処理」するなら、 順に流入してきたデータを全て一時的にどこかに溜めて(バッファ)、 溜め終わってから、そこのデータの末尾から順に流出させる必要がある そのバッファをどうやって作るか、どうやってデータの出し入れをするか、 ということが問題になるが、遅延評価を実現する仕組みのおかげで、 Haskell(の大抵の実装)ではそれを意識しなくてもできてしまう 上の方のレスで問題視された「ふつける」に載ってる方法だ getContents 関数から流出した(リストで表現された)ストリームが reverse 関数に流入してくる 遅延評価の仕組みにより、reverse 関数はリストの内容は評価しない 後で評価する可能性がある未評価のデータはメモリ内に残り続ける この部分がストリームを逆順にたどるための「バッファ」の役割を果たしている
385 名前:デフォルトの名無しさん mailto:sage [2012/01/26(木) 22:51:34.19 ] >>383 おっしゃるとおり。 とりあえず、unsafe使わずに書けるかやってみただけで効率は良くない。 ついでに、ちょっと間違ってて10行以上取ってきます。 遅延IO使えばもっとシンプルに効率よく取ってこれるよ。 ちなみに、遅延評価とバッファは全く関係ない。 ファイルを逆から読むのにバッファは必要ない。
386 名前:デフォルトの名無しさん mailto:sage [2012/01/26(木) 23:11:31.79 ] >>385 > ちなみに、遅延評価とバッファは全く関係ない。 > ファイルを逆から読むのにバッファは必要ない。 ファイルを逆から読むのにバッファを必要としない方法もあることは分かっている >>384 で私が言ったのは、「ストリームとして扱う場合はバッファを必要とする」 ということだ ストリームというのは、パケット通信などのように、 ある塊のデータ群が一列に順に一つずつ流れる、あるいは流すこと 順に流入してきたものを逆順に流出させるには、バッファが絶対に必要だ そのバッファの仕組みをプログラマが意識して自分で作る必要があるかどうかは別だが 確かに遅延評価とバッファに直接の関係はない だが、上記の「ストリームの逆順流出」において 遅延評価を実現させる為の内部の仕組みがたまたまバッファの役割を果たす もう一度言うが、あくまで >>376 のレスを受けて、 「内部処理もストリームとして扱う場合」の話をしている (それが非効率的な事も分かっている)
387 名前:デフォルトの名無しさん mailto:sage [2012/01/26(木) 23:42:32.23 ] よくわからん。 もしhGetContentsが遅延評価でなく先行評価だったとしたら、 その「ストリームの逆順流出」プログラムはどう変わるんだ? どっちにしてもプログラムはhead n $ reverse $ ... なんじゃないのか。
388 名前:デフォルトの名無しさん mailto:sage [2012/01/27(金) 00:05:03.45 ] >>387 > もしhGetContentsが遅延評価でなく先行評価だったとしたら、 > その「ストリームの逆順流出」プログラムはどう変わるんだ? そんなことは知らん 先行評価だった場合にGHCが内部でどのような実装をしてくるのか俺には分からない 初めの >>380 では端折ったが、>>382 からはずっと、 遅延評価を実現する為に使われている内部の仕組みが、 ストリームとして流れてくるデータ順の逆転という処理において バッファとして機能することだけを話しているんだが ちなみに、この目的で内部の仕組みがバッファとして機能するのは、 hGetContents の処理ではなく reverse の処理をGHCが実行ファイルに埋め込む部分だ
389 名前:デフォルトの名無しさん mailto:sage [2012/01/27(金) 00:07:50.19 ] おれは言わんとしてることがわかったけど、 もう少しわかりやすく説明したほうがいいと思うよ。
390 名前:デフォルトの名無しさん mailto:sage [2012/01/27(金) 00:20:31.26 ] >>389 了解した、努力する
391 名前:デフォルトの名無しさん mailto:sage [2012/01/27(金) 00:21:30.05 ] 説明ぷりーず。 一応、WHNF簡約やGHCのSTGマシンあたりの実装は理解してるつもり。
392 名前:デフォルトの名無しさん [2012/01/27(金) 00:43:19.91 ] チュートリアルをやってるのですが、最初で詰まってます。 以下のboomBangsという関数定義でチュートリアルのままなのですが、自分の環境だとエラーになります。 どこが間違ってるのでしょうか。ghci 6.12.1です。 Prelude> boomBangs xs = [if x < 10 then "BOOM!" else "BANG!" | x <- xs, odd x] <interactive>:1:13: parse error on input `=' Prelude> どうかよろしくお願いします。
393 名前:デフォルトの名無しさん mailto:sage [2012/01/27(金) 00:55:24.00 ] Prelude> let boomBangs xs = [if x < 10 then "BOOM!" else "BANG!" | x <- xs, odd x]
394 名前:デフォルトの名無しさん [2012/01/27(金) 01:05:23.28 ] 動きました。ありがとうございました。 Prelude> let boomBangs xs = [if x < 10 then "BOOM!" else "BANG!" | x <- xs, odd x] *** Parser: *** Desugar: *** Simplify: *** CorePrep: *** ByteCodeGen: Prelude> boomBangs [1,2,3,4,5] *** Parser: *** Desugar: *** Simplify: *** CorePrep: *** ByteCodeGen: ["BOOM!","BOOM!","BOOM!"]
395 名前:デフォルトの名無しさん mailto:sage [2012/01/27(金) 01:13:49.09 ] >>391 あんまり難しい話じゃなくて、C言語とかでも、Seekなしで、 ファイルの先頭からシーケンシャルアクセスしかできないとしたら、 最後10行のデータ取ろうと思うと、どうしても直近10行はバッファ しとかないといけないでしょ? Haskellは、このバッファを意識しないでも、自動でやってくれる って言ってるんだと思うよ。 遅延評価がバッファしてるわけじゃないけど、バッファしてるように 見えなくもない。
396 名前:デフォルトの名無しさん mailto:sage [2012/01/27(金) 02:26:27.98 ] Haskellも結局クリーンで美しいカルト言語だったんだお 設計外のことを無理にやらせれて破綻するんだお
397 名前:デフォルトの名無しさん mailto:sage [2012/01/27(金) 02:49:49.78 ] ということにしたいのれすね?
398 名前:デフォルトの名無しさん mailto:sage [2012/01/27(金) 03:01:28.89 ] 実際にやってみたけど、「ふつうの」に書いてある元々の「効率の悪い」 tail に 10 GB ていどのファイルを食わせても、5 秒もかからないんだよね。 これが分単位になるのなら考えてもいいけど、そうでなければ簡潔さの ほうが大事だと思う。 “「効率」についてうんぬんする人々は、たいていの場合主として本番計算に 計算機資源がどのくらい使われるか、という点にばかり着目していて、コンパ イルしたり、虫取りしたり、その他さまざまなやりそこないをしたりしながら 本番計算にそなえるために消費される人間の時間と計算機の時間を考えに入れ ていないのである。” (ソフトウェア作法 p.132)
399 名前:デフォルトの名無しさん mailto:sage [2012/01/27(金) 03:03:28.54 ] ごめん、10GB は嘘だわ。10MB ね。
400 名前:デフォルトの名無しさん mailto:sage [2012/01/27(金) 03:13:57.42 ] ちなみに自分は後ろから読む tail コマンドを昔 C (Pascal だったかも)で書 いてみたことがあるけど、 * ファイルが改行で終わる場合と終わっていない場合を分ける * バッファの先頭から行がはじまっているか、その前からつながっているかを分ける とか、細かい場合分けがあって、予想したより面倒だった。
401 名前:デフォルトの名無しさん mailto:sage [2012/01/27(金) 05:53:27.42 ] >>395 正格評価でも、明示的にバッファ取らなくても、 パラメータ渡しをバッファ代わりにできますし…
402 名前:デフォルトの名無しさん mailto:sage [2012/01/27(金) 05:56:04.14 ] >>398 > これが分単位になるのなら考えてもいいけど、そうでなければ簡潔さの > ほうが大事だと思う。 んなこたーない。 > “「効率」についてうんぬんする人々は、たいていの場合主として本番計算に > 計算機資源がどのくらい使われるか、という点にばかり着目していて、コンパ > イルしたり、虫取りしたり、その他さまざまなやりそこないをしたりしながら > 本番計算にそなえるために消費される人間の時間と計算機の時間を考えに入れ > ていないのである。” (ソフトウェア作法 p.132) これは数回実行するだけの研究用プログラムについては正しいが、 UNIXのtailコマンドのように1度書かれたソースを莫大な回数実行する場合には 詰められる無駄は詰めたほうがいい。
403 名前:デフォルトの名無しさん mailto:sage [2012/01/27(金) 06:59:03.58 ] 正格な評価でも10行分のキューにストリームから一行読んでは突っ込んでいくだけでしょ 別にC言語でも数分で書けるから特にHaskellを使う利点はないよね
404 名前:デフォルトの名無しさん mailto:sage [2012/01/27(金) 07:36:42.85 ] >>401 同じ事を繰り返すが 私は正格評価の事については一言も触れいてない 正格評価ではバッファを意識する必要がある、 なんて私のレスが何処かに書いてあるか? 私は一貫して ・ストリームとして処理するならバッファが必要 ・遅延評価を実現する仕組みがバッファとして機能している この2点しか述べていない 「遅延評価とバッファの関係」を質問されたから、 正格評価の事まで話に絡める必要は無いだろ 別に遅延評価vs正格評価でどちらが有利か戦わせているわけではない 正格評価でも明示的にバッファ取らなくてもいい と貴方が言うのなら、きっとそうなんだろ それは私の話とはたぶん関係ないと思うから、 それがどうかしたのか、としか言いようがない ちなみに、私の話とは別の事として訊くのだが、 > パラメータ渡しをバッファ代わりにする それはパラメータでバッファを渡しているのではないか? 遅延評価を実現する仕組みでたまたま機能するバッファの方は、 バッファを作っているという意識すら感じずにプログラムできるが 「正格評価+ストリーミング処理+パラメータ渡し」 これでバッファを意識しなくてもいいプログラムを書いてみてくれ ちょっと興味ある
405 名前:デフォルトの名無しさん mailto:sage [2012/01/27(金) 07:46:54.83 ] 引数として先頭トークンと継続を渡せばいいんじゃね?
406 名前:デフォルトの名無しさん mailto:sage [2012/01/27(金) 07:49:56.57 ] >>391 以下の部分で遅延評価とバッファの関係を簡単に述べている どこの部分の詳細な説明を求めているのか具体的に言ってほしい >>384 > 遅延評価の仕組みにより、reverse 関数はリストの内容は評価しない > 後で評価する可能性がある未評価のデータはメモリ内に残り続ける > この部分がストリームを逆順にたどるための「バッファ」の役割を果たしている
407 名前:デフォルトの名無しさん mailto:sage [2012/01/27(金) 08:04:10.58 ] アホかHaskellでもバッファは意識しろよ そんなんだからアホ的非効率コードを書くんだよ
408 名前:デフォルトの名無しさん mailto:sage [2012/01/27(金) 08:13:37.12 ] どうでも良くなってきたが、、、 正格評価、遅延評価とかはバッファと関係ないと思います。 というか、バッファされてる時点で評価済みで遅延してない、、、 正格でも遅延でもたぶん同じように書けます。
409 名前:デフォルトの名無しさん mailto:sage [2012/01/27(金) 08:23:27.08 ] 手元にある一番大きなプレーンテキストは MySQL のダンプ(1.3GB)だったので, これを「ふつうのHaskell」版の tail コマンドに食わせてみたが、メモリオー バーで時間計測できず(笑)。ファイル丸ごと reverse はさすがにないな。 ただ、個人的にはテキストファイルをランダムアクセスするのは(使用言語が何 であれ)プログラムが無意味に複雑化するので反対。sort とかなら高速化の意 味はあるだろうけれど、tail コマンドをそんなに速くしてどうするの、っていう かんじ。 Haskell なら、このていどでいいはず。これなら本にのせても場所を取らないし、 大きなファイルでも動作する。 import System dotail :: Int -> [a] -> [a] dotail n xs = if null (drop n xs) then take n xs else dotail n $ tail xs main = do {args <- getArgs; cs <- getContents; putStr $ unlines $ dotail (read (head args)::Int) (lines cs)} 1.3 GB で 13分だった。Haskell の入出力の遅さを考えればまあまあじゃないかな。 ちなみに同じファイルに対して行数カウント getContents >>= print.length.lines だと 8分35秒。Java (BufferedReader.readLine 使用) や Perl で同じことを やると1分40秒から 1分50秒くらい。wc -l コマンドだと 36秒。
410 名前:デフォルトの名無しさん mailto:sage [2012/01/27(金) 08:30:16.99 ] おまいらこのあとは tail -f の実装が待ってますよ
411 名前:デフォルトの名無しさん mailto:sage [2012/01/27(金) 10:25:32.57 ] ふつうに実装するとIO (IO String)が出てくるから それよりはunsafeでもIO [String]にしたいってことなのか
412 名前:デフォルトの名無しさん mailto:sage [2012/01/27(金) 10:39:57.79 ] System.IO.MMap.Lazy
413 名前:デフォルトの名無しさん mailto:sage [2012/01/27(金) 11:12:49.26 ] tailなんて巨大ログをすばやく確認したい時ぐらいなんだから いちいち先頭から1行ずつ読むとか糞遅かったら誰も使わんだろ 用途を満たさない物なんか設計してどうする 言語の作法なんて関係ない
414 名前:デフォルトの名無しさん mailto:sage [2012/01/27(金) 11:16:44.14 ] >>410 それは簡単じゃない? Control.Concurrent の threadWaitRead で待って、サイズが変わってたら その分を出力するだけでしょ。
415 名前:デフォルトの名無しさん mailto:sage [2012/01/27(金) 11:32:02.97 ] 俺がtail使うのはファイルよりpipeのほうが多いな
416 名前:デフォルトの名無しさん mailto:sage [2012/01/27(金) 12:06:04.37 ] ここで問われているのは、 長年GNUがやってきたように、 過去の他人の成果を丸パクリして、 それでも使われるレベルになるのかどうか? ということだよな
417 名前:デフォルトの名無しさん mailto:sage [2012/01/27(金) 12:47:47.33 ] 儲かるレベルにはならないからポジショントークをする人がひとりもいない という成果に期待しよう
418 名前:デフォルトの名無しさん mailto:sage [2012/01/27(金) 14:20:57.31 ] クソ実装でも十分速いとか言ってる香具師がいるけど、 空読みするファイルが分散fs上に乗ってたら悲惨だなw
419 名前:デフォルトの名無しさん mailto:sage [2012/01/27(金) 16:51:25.37 ] 標準だけで教科書的に綺麗に書くようなオナニーは卒業して 仕事でHaskell使っている人が苦心の末発明したcondoitの使い方覚えろよ
420 名前:デフォルトの名無しさん mailto:sage [2012/01/27(金) 17:07:01.50 ] なにそのコンドームみたいなの?
421 名前:デフォルトの名無しさん mailto:sage [2012/01/27(金) 17:09:06.72 ] conduit
422 名前:デフォルトの名無しさん mailto:sage [2012/01/27(金) 18:37:45.13 ] あれだこれだと意見はいろいろあるだろうが、 にコードが出てきたのがなんと言っても尊い。
423 名前:デフォルトの名無しさん mailto:sage [2012/01/28(土) 11:33:31.74 ] >>288 Template Haskell を少し勉強してみたところ、 やりたいことが実現できそうなことが分かりました 例えば次のように引数をコンパイル時に制限できるんですね f :: Int -> ExpQ f x | x < 0 = fail "error" | otherwise = [| x |] $(f (-1)) ====> error $(f 3) ====> 3 このような事を値構築子でできるようにすれば良いわけですね 調べてみます ありがとうございました
424 名前:デフォルトの名無しさん mailto:sage [2012/01/29(日) 09:15:33.67 ] jutememo.blogspot.com/2011/04/haskell-swap-9.html リストの要素を入れ替えるswap関数は、pythonの方が簡潔なんだな・・・ リストを配列みたいに扱えない言語よりは優位なんだろうけど、そう言う言語と比較するときは配列と比較になるしなぁ・・・
425 名前:デフォルトの名無しさん mailto:sage [2012/01/29(日) 09:30:41.60 ] リストのランダムアクセスは遅いから専用の関数が用意されてないだけ Data.Sequenceならupdateがあるので簡単 swap :: Int -> Int -> Seq a -> Seq a swap i j s = update i (s `index` j) $ update j (s `index` i) s
426 名前:デフォルトの名無しさん mailto:sage [2012/01/29(日) 09:37:27.18 ] よく言語Aより言語Bの方が処理(計算)xを簡単に書ける、というけどさ 言いたいことは分かるけど、「具体的な処理」に関して、 処理後に同じ結果が得られる複数の言語間で「簡潔さを比較」する意味って何なの? >>424 のリストの swap だって、一旦関数にしてしまえば、 あとは Haskell でも同じように簡潔に書けると思うんだが (それがライブラリの大きな役割の一つだし) >>424 のリンク先で考察している方法それ自体は面白いし興味あるけどね
427 名前:デフォルトの名無しさん mailto:sage [2012/01/29(日) 09:44:58.64 ] >>426 いろいろな具体的な(既知の)処理を簡潔に書ける言語があれば、 アプリケーション固有の(未知の)処理も簡潔に書ける可能性が高いからだろ 未知の処理だって、なんらかの既知の処理に似ていることが殆どだ ということを加味すればなおさら
428 名前:デフォルトの名無しさん mailto:sage [2012/01/29(日) 09:53:41.16 ] そりゃ、できることを比較したらどれも同じになるから比較にならんだろ。 言語の比較は、簡潔に書きやすいとかできるコードが速いとか、デバッグ しやすいとかになるわ。ライブラリだって簡潔に書けるほうが充実させや すいしな。
429 名前:デフォルトの名無しさん mailto:sage [2012/01/29(日) 10:07:36.20 ] ハスケルのほうが簡単に書ける時には 「ハスケル最強」 ハスケルのほうが煩雑になってしまう時には 「そんな比較意味なくね?」
430 名前:デフォルトの名無しさん mailto:sage [2012/01/29(日) 10:15:41.39 ] >>429 それは、逆も同じだけどね。 ハスケルのほうが簡単に書ける時には 「そんなの意味なくね」 ハスケルのほうが煩雑になってしまう時には 「ハスケル使えねぇ」 用途考えずに比較なんて意味ないね。
431 名前:デフォルトの名無しさん mailto:sage [2012/01/29(日) 10:35:32.33 ] >>427 いや、だから一度関数になってしまえば、「簡潔さはほぼ同じ」になるわけでしょ 最初に比較して言語Aの方が簡潔だった、でも関数にしたから言語Bも同じなった >>424 の言う「優位な言語」というのは、どの時点で比較したものなの? 仮に言語Bが関数化した結果、言語Aよりも簡潔になったら、言語間の優位さは逆転するの? そういうことで逆転してしまうのなら、それはその「具体的な処理に関する」 簡潔さの言語間の比較とは言えないだろう その具体的な処理に被せるインターフェースの部分のおかげで簡潔になったのだから また、そんなことで逆転したとは言えないのなら、そもそも比較して 言語Aの方が優位だとか言うことの意義が見いだせない 私の経験上、実用的なアプリ内の数多ある個別具体的な処理に関して、 それらを最も得意とする言語(やパラダイム)は複数に分散する ある特定の処理をするのに言語Aが優位だからという理由で、 そのアプリを作るのに言語Aを選ぶことは、実際のところ滅多にない 普通は自分やチームが得意としている言語であったり、 個別具体的な処理ではなく全体の求められる処理速度やメンテのしやすさなどで決定される >>428 今の時代、広く使われている言語なら、どの言語でもライブラリは充実している 充実度の差の理由に言語の簡潔さが関わる割合は、比較して議論するほど高くはないと思うが
432 名前:デフォルトの名無しさん mailto:sage [2012/01/29(日) 10:58:44.59 ] ある処理を実験する複数のプログラムを一つのファイルに書いていました。 (初めはファイルを分けるのが面倒に思えたから) あるプログラムを実験するときは別のプログラムをコメントアウトしたりして。 なので、ファイルのトップには import が大量に書かれています。 実験が終わって、採用するプログラムを一つに絞ったので、 それを正式にちゃんとしたファイルに分けて保存したいのですが、 そのプログラムを実行するのにどの import が必要なのか、 ごちゃごちゃしてて分からなくなりました。 とりあえずそのプログラムだけ別ファイルに移してコンパイルしてみて、 モジュール不足の為にコンパイルエラーが出る度に import を追加していけばいいとは思いますが・・・(以前も同じ様なことをしてた) もっと簡単に、あるソースファイル内の識別子を評価するのに不足していて、 かつインストール済みであるライブラリのモジュールの一覧を見る方法はありませんか。
433 名前:427 mailto:sage [2012/01/29(日) 11:08:59.81 ] >>431 俺は>>424 じゃないけど、関数化の前の話をしているつもりだった >また、そんなことで逆転したとは言えないのなら、そもそも比較して >言語Aの方が優位だとか言うことの意義が見いだせない >私の経験上、実用的なアプリ内の数多ある個別具体的な処理に関して、 >それらを最も得意とする言語(やパラダイム)は複数に分散する もちろん。でも、実際的なアプリが色んな処理から成っているからこそ、 言語には極端な苦手分野がないほうが良いし、なるべく広範囲のコードを 簡潔に書けるのが良いということになる たとえばランダムアクセス可能なデータ構造をすごく扱いにくい言語があったら、 その言語で書き易いアプリはかなり限定される それから、アプリごとに多用される処理の傾向も違う 行列演算中心のアプリもあるし、DBアクセス中心のアプリもあるし、両方やるのもある
434 名前:デフォルトの名無しさん mailto:sage [2012/01/29(日) 11:13:25.04 ] >>432 全部のファイルに全部のimportをコピーして、とりあえずコンパイルを通す コンパイルが通ったら-fwarn-unused-importsで不要なインポートを一掃
435 名前:デフォルトの名無しさん mailto:sage [2012/01/29(日) 11:16:53.53 ] >>431 長くて読む気しないな。 言語比較なんてナンセンスだと思うが。言語の優劣なんて個人個人で違うし。 関数化すれば0になるかもしれないけど、関数化するまでのコストは? ライブラリになってないところの、作成コストは? ライブラリの学習コストは? ライブラリは十分充実してる?そしたら自分でプログラムなんて書かんわ。
436 名前:デフォルトの名無しさん mailto:sage [2012/01/29(日) 11:30:01.60 ] >>434 なるほど、逆でしたか 不要な import を省いていくんですね ありがとうございました
437 名前:デフォルトの名無しさん mailto:sage [2012/01/29(日) 12:41:36.12 ] >>431 うーん、同じ処理の関数化の比較は、コードの長さとかだけじゃなく、関数化する際の概念とか手法とかがプログラマ・あるいは初心者に思いつきやすいか?とかの意味でも比較の意味はあると思う。 >>424 のURL先ではpythonは配列的にも使えるリストのために、値の交換が得意な配列的な処理になってるけど、配列は配列。リストはリストとして扱う手続き型言語の場合、 1、リストの中身を配列に移す 2、配列で値を交換 3、配列の中身をリストに戻す と言う処理になる Haskellだと >>424 の9つの方法の内、初心者にも出来そうな一つ目と二つ目の方法は基本 1.リストを分割する (iより前のリスト、i、iとjの間のリスト、j、jの後ろのリスト) 2.値を交換した状態のリストとして結合しなおす という処理になる
438 名前:デフォルトの名無しさん mailto:sage [2012/01/29(日) 12:53:23.82 ] >>437 > 1、リストの中身を配列に移す > 2、配列で値を交換 > 3、配列の中身をリストに戻す > > と言う処理になる そんな馬鹿なコードを書くのはプログラム初めて1ヶ月とかの初心者だけだろw