関数型プログラミング言語Haskell Part17
■ このスレッドは過去ログ倉庫に格納されています
0001デフォルトの名無しさん
2012/01/02(月) 22:19:28.26ttp://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/
0369デフォルトの名無しさん
2012/01/25(水) 04:13:13.510370デフォルトの名無しさん
2012/01/25(水) 06:30:19.08これを使ってO(1)のtailを作れたら神だな。
0371デフォルトの名無しさん
2012/01/25(水) 07:24:35.01「処理速度を出す為」だと思ってるんじゃないだろうか
0372デフォルトの名無しさん
2012/01/25(水) 07:57:17.27普通に書けばファイルサイズに対してO(1)時間になるんじゃね?
0373デフォルトの名無しさん
2012/01/25(水) 21:53:21.47ファイルサイズチェックしてないので、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)
0374デフォルトの名無しさん
2012/01/25(水) 21:58:39.36main = 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)
0375デフォルトの名無しさん
2012/01/26(木) 15:33:16.32プログラムになるだろうけど、
強引に別のパラダイムのものに合わせようとすると悲惨になるのは当然じゃろ?
そのパラダイムに応じた方法を模索していくしかないような。
Haskellって他よりパラダイムが明確なだけに得手不得手があるのは
仕方がなさそうよね。
0376デフォルトの名無しさん
2012/01/26(木) 16:55:41.77関数型言語のパラダイムと親和性があると思うけどな
Broken Pipe
0377デフォルトの名無しさん
2012/01/26(木) 17:41:23.30結局、メタパラダイムとかいうのは的外れってことだね
0379デフォルトの名無しさん
2012/01/26(木) 20:04:34.510380デフォルトの名無しさん
2012/01/26(木) 20:23:58.12標準入出力をストリームとして扱うのはインターフェースの部分
内部では tail が代表するように単純にストリームでは扱っていない
関数型は無限リストや継続などでストリームを上手く表現できるが、
今回話題になっている話はインターフェースじゃなくて内部処理の方
正方向で流れてくる情報を逆方向からたどるというのは、
ある意味ストリームとは対極にある処理だと思う
内部処理もストリームにする事に拘るなら、
逆方向にする時にバッファにため込む必要がある
(たまたま Haskell では遅延評価のおかげでそのバッファ処理を自動化できるが)
0381デフォルトの名無しさん
2012/01/26(木) 20:33:13.400382デフォルトの名無しさん
2012/01/26(木) 20:43:46.18正格評価ではバッファを普通にはできない、
と言っているように感じたのか
それなら申し訳ない
遅延評価という仕組みを実現するためのGHCの実装のおかげで、
バッファを作らなきゃいけないことを意識する必要がない
という意味で言ったのだ
念のために言い添えておくと、処理速度などの話とは全く別のことだ
0383デフォルトの名無しさん
2012/01/26(木) 21:37:21.78少なくとも>374のコードは再帰するたびに毎回ファイル末尾から読み直してるようにみえる。
行のサイズ = blockSizeのファイルに対して、
tail nを計算するのにO(n^2)の処理を行っているのでは?
0384デフォルトの名無しさん
2012/01/26(木) 22:05:50.63> 遅延評価とバッファの関係がよくわからないな。
>>374 のコードは今回の私の話とは全く関係ない
>>376 のストリームの話だ
逆順に指定行数を出力するという処理を「ストリームとして処理」するなら、
順に流入してきたデータを全て一時的にどこかに溜めて(バッファ)、
溜め終わってから、そこのデータの末尾から順に流出させる必要がある
そのバッファをどうやって作るか、どうやってデータの出し入れをするか、
ということが問題になるが、遅延評価を実現する仕組みのおかげで、
Haskell(の大抵の実装)ではそれを意識しなくてもできてしまう
上の方のレスで問題視された「ふつける」に載ってる方法だ
getContents 関数から流出した(リストで表現された)ストリームが
reverse 関数に流入してくる
遅延評価の仕組みにより、reverse 関数はリストの内容は評価しない
後で評価する可能性がある未評価のデータはメモリ内に残り続ける
この部分がストリームを逆順にたどるための「バッファ」の役割を果たしている
0385デフォルトの名無しさん
2012/01/26(木) 22:51:34.19おっしゃるとおり。
とりあえず、unsafe使わずに書けるかやってみただけで効率は良くない。
ついでに、ちょっと間違ってて10行以上取ってきます。
遅延IO使えばもっとシンプルに効率よく取ってこれるよ。
ちなみに、遅延評価とバッファは全く関係ない。
ファイルを逆から読むのにバッファは必要ない。
0386デフォルトの名無しさん
2012/01/26(木) 23:11:31.79> ちなみに、遅延評価とバッファは全く関係ない。
> ファイルを逆から読むのにバッファは必要ない。
ファイルを逆から読むのにバッファを必要としない方法もあることは分かっている
>>384 で私が言ったのは、「ストリームとして扱う場合はバッファを必要とする」
ということだ
ストリームというのは、パケット通信などのように、
ある塊のデータ群が一列に順に一つずつ流れる、あるいは流すこと
順に流入してきたものを逆順に流出させるには、バッファが絶対に必要だ
そのバッファの仕組みをプログラマが意識して自分で作る必要があるかどうかは別だが
確かに遅延評価とバッファに直接の関係はない
だが、上記の「ストリームの逆順流出」において
遅延評価を実現させる為の内部の仕組みがたまたまバッファの役割を果たす
もう一度言うが、あくまで >>376 のレスを受けて、
「内部処理もストリームとして扱う場合」の話をしている
(それが非効率的な事も分かっている)
0387デフォルトの名無しさん
2012/01/26(木) 23:42:32.23もしhGetContentsが遅延評価でなく先行評価だったとしたら、
その「ストリームの逆順流出」プログラムはどう変わるんだ?
どっちにしてもプログラムはhead n $ reverse $ ...
なんじゃないのか。
0388デフォルトの名無しさん
2012/01/27(金) 00:05:03.45> もしhGetContentsが遅延評価でなく先行評価だったとしたら、
> その「ストリームの逆順流出」プログラムはどう変わるんだ?
そんなことは知らん
先行評価だった場合にGHCが内部でどのような実装をしてくるのか俺には分からない
初めの >>380 では端折ったが、>>382 からはずっと、
遅延評価を実現する為に使われている内部の仕組みが、
ストリームとして流れてくるデータ順の逆転という処理において
バッファとして機能することだけを話しているんだが
ちなみに、この目的で内部の仕組みがバッファとして機能するのは、
hGetContents の処理ではなく reverse の処理をGHCが実行ファイルに埋め込む部分だ
0389デフォルトの名無しさん
2012/01/27(金) 00:07:50.19もう少しわかりやすく説明したほうがいいと思うよ。
0390デフォルトの名無しさん
2012/01/27(金) 00:20:31.26了解した、努力する
0391デフォルトの名無しさん
2012/01/27(金) 00:21:30.05一応、WHNF簡約やGHCのSTGマシンあたりの実装は理解してるつもり。
0392デフォルトの名無しさん
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>
どうかよろしくお願いします。
0393デフォルトの名無しさん
2012/01/27(金) 00:55:24.000394デフォルトの名無しさん
2012/01/27(金) 01:05:23.28Prelude> 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!"]
0395デフォルトの名無しさん
2012/01/27(金) 01:13:49.09あんまり難しい話じゃなくて、C言語とかでも、Seekなしで、
ファイルの先頭からシーケンシャルアクセスしかできないとしたら、
最後10行のデータ取ろうと思うと、どうしても直近10行はバッファ
しとかないといけないでしょ?
Haskellは、このバッファを意識しないでも、自動でやってくれる
って言ってるんだと思うよ。
遅延評価がバッファしてるわけじゃないけど、バッファしてるように
見えなくもない。
0396デフォルトの名無しさん
2012/01/27(金) 02:26:27.98設計外のことを無理にやらせれて破綻するんだお
0397デフォルトの名無しさん
2012/01/27(金) 02:49:49.780398デフォルトの名無しさん
2012/01/27(金) 03:01:28.89tail に 10 GB ていどのファイルを食わせても、5 秒もかからないんだよね。
これが分単位になるのなら考えてもいいけど、そうでなければ簡潔さの
ほうが大事だと思う。
“「効率」についてうんぬんする人々は、たいていの場合主として本番計算に
計算機資源がどのくらい使われるか、という点にばかり着目していて、コンパ
イルしたり、虫取りしたり、その他さまざまなやりそこないをしたりしながら
本番計算にそなえるために消費される人間の時間と計算機の時間を考えに入れ
ていないのである。” (ソフトウェア作法 p.132)
0399デフォルトの名無しさん
2012/01/27(金) 03:03:28.540400デフォルトの名無しさん
2012/01/27(金) 03:13:57.42いてみたことがあるけど、
* ファイルが改行で終わる場合と終わっていない場合を分ける
* バッファの先頭から行がはじまっているか、その前からつながっているかを分ける
とか、細かい場合分けがあって、予想したより面倒だった。
0401デフォルトの名無しさん
2012/01/27(金) 05:53:27.42正格評価でも、明示的にバッファ取らなくても、
パラメータ渡しをバッファ代わりにできますし…
0402デフォルトの名無しさん
2012/01/27(金) 05:56:04.14> これが分単位になるのなら考えてもいいけど、そうでなければ簡潔さの
> ほうが大事だと思う。
んなこたーない。
> “「効率」についてうんぬんする人々は、たいていの場合主として本番計算に
> 計算機資源がどのくらい使われるか、という点にばかり着目していて、コンパ
> イルしたり、虫取りしたり、その他さまざまなやりそこないをしたりしながら
> 本番計算にそなえるために消費される人間の時間と計算機の時間を考えに入れ
> ていないのである。” (ソフトウェア作法 p.132)
これは数回実行するだけの研究用プログラムについては正しいが、
UNIXのtailコマンドのように1度書かれたソースを莫大な回数実行する場合には
詰められる無駄は詰めたほうがいい。
0403デフォルトの名無しさん
2012/01/27(金) 06:59:03.58別にC言語でも数分で書けるから特にHaskellを使う利点はないよね
0404デフォルトの名無しさん
2012/01/27(金) 07:36:42.85同じ事を繰り返すが
私は正格評価の事については一言も触れいてない
正格評価ではバッファを意識する必要がある、
なんて私のレスが何処かに書いてあるか?
私は一貫して
・ストリームとして処理するならバッファが必要
・遅延評価を実現する仕組みがバッファとして機能している
この2点しか述べていない
「遅延評価とバッファの関係」を質問されたから、
正格評価の事まで話に絡める必要は無いだろ
別に遅延評価vs正格評価でどちらが有利か戦わせているわけではない
正格評価でも明示的にバッファ取らなくてもいい
と貴方が言うのなら、きっとそうなんだろ
それは私の話とはたぶん関係ないと思うから、
それがどうかしたのか、としか言いようがない
ちなみに、私の話とは別の事として訊くのだが、
> パラメータ渡しをバッファ代わりにする
それはパラメータでバッファを渡しているのではないか?
遅延評価を実現する仕組みでたまたま機能するバッファの方は、
バッファを作っているという意識すら感じずにプログラムできるが
「正格評価+ストリーミング処理+パラメータ渡し」
これでバッファを意識しなくてもいいプログラムを書いてみてくれ
ちょっと興味ある
0405デフォルトの名無しさん
2012/01/27(金) 07:46:54.830406デフォルトの名無しさん
2012/01/27(金) 07:49:56.57以下の部分で遅延評価とバッファの関係を簡単に述べている
どこの部分の詳細な説明を求めているのか具体的に言ってほしい
>>384
> 遅延評価の仕組みにより、reverse 関数はリストの内容は評価しない
> 後で評価する可能性がある未評価のデータはメモリ内に残り続ける
> この部分がストリームを逆順にたどるための「バッファ」の役割を果たしている
0407デフォルトの名無しさん
2012/01/27(金) 08:04:10.58そんなんだからアホ的非効率コードを書くんだよ
0408デフォルトの名無しさん
2012/01/27(金) 08:13:37.12正格評価、遅延評価とかはバッファと関係ないと思います。
というか、バッファされてる時点で評価済みで遅延してない、、、
正格でも遅延でもたぶん同じように書けます。
0409デフォルトの名無しさん
2012/01/27(金) 08:23:27.08これを「ふつうの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秒。
0410デフォルトの名無しさん
2012/01/27(金) 08:30:16.990411デフォルトの名無しさん
2012/01/27(金) 10:25:32.57それよりはunsafeでもIO [String]にしたいってことなのか
0412デフォルトの名無しさん
2012/01/27(金) 10:39:57.790413デフォルトの名無しさん
2012/01/27(金) 11:12:49.26いちいち先頭から1行ずつ読むとか糞遅かったら誰も使わんだろ
用途を満たさない物なんか設計してどうする
言語の作法なんて関係ない
0414デフォルトの名無しさん
2012/01/27(金) 11:16:44.14それは簡単じゃない?
Control.Concurrent の threadWaitRead で待って、サイズが変わってたら
その分を出力するだけでしょ。
0415デフォルトの名無しさん
2012/01/27(金) 11:32:02.970416デフォルトの名無しさん
2012/01/27(金) 12:06:04.37長年GNUがやってきたように、
過去の他人の成果を丸パクリして、
それでも使われるレベルになるのかどうか?
ということだよな
0417デフォルトの名無しさん
2012/01/27(金) 12:47:47.33という成果に期待しよう
0418デフォルトの名無しさん
2012/01/27(金) 14:20:57.31空読みするファイルが分散fs上に乗ってたら悲惨だなw
0419デフォルトの名無しさん
2012/01/27(金) 16:51:25.37仕事でHaskell使っている人が苦心の末発明したcondoitの使い方覚えろよ
0420デフォルトの名無しさん
2012/01/27(金) 17:07:01.500421デフォルトの名無しさん
2012/01/27(金) 17:09:06.720422デフォルトの名無しさん
2012/01/27(金) 18:37:45.13にコードが出てきたのがなんと言っても尊い。
0423デフォルトの名無しさん
2012/01/28(土) 11:33:31.74Template Haskell を少し勉強してみたところ、
やりたいことが実現できそうなことが分かりました
例えば次のように引数をコンパイル時に制限できるんですね
f :: Int -> ExpQ
f x | x < 0 = fail "error"
| otherwise = [| x |]
$(f (-1)) ====> error
$(f 3) ====> 3
このような事を値構築子でできるようにすれば良いわけですね
調べてみます
ありがとうございました
0424デフォルトの名無しさん
2012/01/29(日) 09:15:33.67リストの要素を入れ替えるswap関数は、pythonの方が簡潔なんだな・・・
リストを配列みたいに扱えない言語よりは優位なんだろうけど、そう言う言語と比較するときは配列と比較になるしなぁ・・・
0425デフォルトの名無しさん
2012/01/29(日) 09:30:41.60Data.Sequenceならupdateがあるので簡単
swap :: Int -> Int -> Seq a -> Seq a
swap i j s = update i (s `index` j) $ update j (s `index` i) s
0426デフォルトの名無しさん
2012/01/29(日) 09:37:27.18言いたいことは分かるけど、「具体的な処理」に関して、
処理後に同じ結果が得られる複数の言語間で「簡潔さを比較」する意味って何なの?
>>424 のリストの swap だって、一旦関数にしてしまえば、
あとは Haskell でも同じように簡潔に書けると思うんだが
(それがライブラリの大きな役割の一つだし)
>>424 のリンク先で考察している方法それ自体は面白いし興味あるけどね
0427デフォルトの名無しさん
2012/01/29(日) 09:44:58.64いろいろな具体的な(既知の)処理を簡潔に書ける言語があれば、
アプリケーション固有の(未知の)処理も簡潔に書ける可能性が高いからだろ
未知の処理だって、なんらかの既知の処理に似ていることが殆どだ
ということを加味すればなおさら
0428デフォルトの名無しさん
2012/01/29(日) 09:53:41.16言語の比較は、簡潔に書きやすいとかできるコードが速いとか、デバッグ
しやすいとかになるわ。ライブラリだって簡潔に書けるほうが充実させや
すいしな。
0429デフォルトの名無しさん
2012/01/29(日) 10:07:36.20「ハスケル最強」
ハスケルのほうが煩雑になってしまう時には
「そんな比較意味なくね?」
0430デフォルトの名無しさん
2012/01/29(日) 10:15:41.39それは、逆も同じだけどね。
ハスケルのほうが簡単に書ける時には
「そんなの意味なくね」
ハスケルのほうが煩雑になってしまう時には
「ハスケル使えねぇ」
用途考えずに比較なんて意味ないね。
0431デフォルトの名無しさん
2012/01/29(日) 10:35:32.33いや、だから一度関数になってしまえば、「簡潔さはほぼ同じ」になるわけでしょ
最初に比較して言語Aの方が簡潔だった、でも関数にしたから言語Bも同じなった
>>424 の言う「優位な言語」というのは、どの時点で比較したものなの?
仮に言語Bが関数化した結果、言語Aよりも簡潔になったら、言語間の優位さは逆転するの?
そういうことで逆転してしまうのなら、それはその「具体的な処理に関する」
簡潔さの言語間の比較とは言えないだろう
その具体的な処理に被せるインターフェースの部分のおかげで簡潔になったのだから
また、そんなことで逆転したとは言えないのなら、そもそも比較して
言語Aの方が優位だとか言うことの意義が見いだせない
私の経験上、実用的なアプリ内の数多ある個別具体的な処理に関して、
それらを最も得意とする言語(やパラダイム)は複数に分散する
ある特定の処理をするのに言語Aが優位だからという理由で、
そのアプリを作るのに言語Aを選ぶことは、実際のところ滅多にない
普通は自分やチームが得意としている言語であったり、
個別具体的な処理ではなく全体の求められる処理速度やメンテのしやすさなどで決定される
>>428
今の時代、広く使われている言語なら、どの言語でもライブラリは充実している
充実度の差の理由に言語の簡潔さが関わる割合は、比較して議論するほど高くはないと思うが
0432デフォルトの名無しさん
2012/01/29(日) 10:58:44.59(初めはファイルを分けるのが面倒に思えたから)
あるプログラムを実験するときは別のプログラムをコメントアウトしたりして。
なので、ファイルのトップには import が大量に書かれています。
実験が終わって、採用するプログラムを一つに絞ったので、
それを正式にちゃんとしたファイルに分けて保存したいのですが、
そのプログラムを実行するのにどの import が必要なのか、
ごちゃごちゃしてて分からなくなりました。
とりあえずそのプログラムだけ別ファイルに移してコンパイルしてみて、
モジュール不足の為にコンパイルエラーが出る度に
import を追加していけばいいとは思いますが・・・(以前も同じ様なことをしてた)
もっと簡単に、あるソースファイル内の識別子を評価するのに不足していて、
かつインストール済みであるライブラリのモジュールの一覧を見る方法はありませんか。
0433427
2012/01/29(日) 11:08:59.81俺は>>424じゃないけど、関数化の前の話をしているつもりだった
>また、そんなことで逆転したとは言えないのなら、そもそも比較して
>言語Aの方が優位だとか言うことの意義が見いだせない
>私の経験上、実用的なアプリ内の数多ある個別具体的な処理に関して、
>それらを最も得意とする言語(やパラダイム)は複数に分散する
もちろん。でも、実際的なアプリが色んな処理から成っているからこそ、
言語には極端な苦手分野がないほうが良いし、なるべく広範囲のコードを
簡潔に書けるのが良いということになる
たとえばランダムアクセス可能なデータ構造をすごく扱いにくい言語があったら、
その言語で書き易いアプリはかなり限定される
それから、アプリごとに多用される処理の傾向も違う
行列演算中心のアプリもあるし、DBアクセス中心のアプリもあるし、両方やるのもある
0434デフォルトの名無しさん
2012/01/29(日) 11:13:25.04全部のファイルに全部のimportをコピーして、とりあえずコンパイルを通す
コンパイルが通ったら-fwarn-unused-importsで不要なインポートを一掃
0435デフォルトの名無しさん
2012/01/29(日) 11:16:53.53長くて読む気しないな。
言語比較なんてナンセンスだと思うが。言語の優劣なんて個人個人で違うし。
関数化すれば0になるかもしれないけど、関数化するまでのコストは?
ライブラリになってないところの、作成コストは?
ライブラリの学習コストは?
ライブラリは十分充実してる?そしたら自分でプログラムなんて書かんわ。
0436デフォルトの名無しさん
2012/01/29(日) 11:30:01.60なるほど、逆でしたか
不要な import を省いていくんですね
ありがとうございました
0437デフォルトの名無しさん
2012/01/29(日) 12:41:36.12うーん、同じ処理の関数化の比較は、コードの長さとかだけじゃなく、関数化する際の概念とか手法とかがプログラマ・あるいは初心者に思いつきやすいか?とかの意味でも比較の意味はあると思う。
>>424のURL先ではpythonは配列的にも使えるリストのために、値の交換が得意な配列的な処理になってるけど、配列は配列。リストはリストとして扱う手続き型言語の場合、
1、リストの中身を配列に移す
2、配列で値を交換
3、配列の中身をリストに戻す
と言う処理になる
Haskellだと
>>424の9つの方法の内、初心者にも出来そうな一つ目と二つ目の方法は基本
1.リストを分割する
(iより前のリスト、i、iとjの間のリスト、j、jの後ろのリスト)
2.値bキした状態bフリストとして血牛しなおす
という処理になる
0438デフォルトの名無しさん
2012/01/29(日) 12:53:23.82> 1、リストの中身を配列に移す
> 2、配列で値を交換
> 3、配列の中身をリストに戻す
>
> と言う処理になる
そんな馬鹿なコードを書くのはプログラム初めて1ヶ月とかの初心者だけだろw
0439デフォルトの名無しさん
2012/01/29(日) 12:55:50.74え、確かにリストのままでも配列的に使えるけど、パフォーマンス的にはこちらは今でも有効だと思うけど・・・
0440デフォルトの名無しさん
2012/01/29(日) 13:03:38.330441デフォルトの名無しさん
2012/01/29(日) 13:05:40.34で、swapの実装という単位で比較した結果、言語Aの方が
関数化する際の概念とか手法とかがプログラマ・あるいは初心者に思いつきやすい
と結論づけられたとして、それからどうなるの?
それが何にどのように、どれくらい活かされる?
例えばHaskellという一言語においてリストをswapするいくつかの方法の中で、
簡潔さ、初心者の理解のしやすさ、計算速度、応用の幅・・・
などで互いに比較しすることの意義は分かる
時と場合によって使い分ける際の自分なりの基準になる
しかし、今存在している言語間で、swap処理などの
抽象度の低い低レベルレイヤーの処理の実装を比較して
優劣を考える意義がよく分からない
せいぜい新言語を作る際に、既存言語を分析する時ぐらいしか、
言語間で比較して優劣を考える意義はなくないか?
0442デフォルトの名無しさん
2012/01/29(日) 13:05:46.19じゃあ、どういう処理を1ヶ月以上たったらしてるの?
0443デフォルトの名無しさん
2012/01/29(日) 13:15:46.010444デフォルトの名無しさん
2012/01/29(日) 13:17:38.11リスト処理を解説する初心者レベルの入門書で
スワップ時にリストの中身を配列に移すなんて方法は、普通は教えない
普通は、双方向リスト・単方向リストの要素がリンクで結ばれていることをまず教える
もしスワップ処理を教えるなら当然その後になるが、
その際はリンクを繋ぎ替える処理で実装する方法を教えるだろう
処理速度云々ではなく、その方が初心者が「リスト処理を理解しやすい」からだ
初心者はリストの特徴を学ぶのが大事だからな
だから、一ヶ月と言わず、初めから配列に移すなんて方法は学ばない
0445デフォルトの名無しさん
2012/01/29(日) 13:23:20.30たった1回のswapのために配列にコピってswapしてリストを再構築するとか、アホだろ。
0446デフォルトの名無しさん
2012/01/29(日) 13:23:33.53今はサイト自体(と運営会社)が無くなっちゃったけど、Haskell入門以前という、プログラミング全くの初心者向けのブログ書いてたんだ
(そして、ネット上の友達(プログラミング未経験者)に読んでもらって、理解できるか確認しながら書いてた)
その関係で、PCがどうやって動いてるかも理解できてない人向けの言語を探してたり
そういう意味で、Haskellは割りと有効だとは思ってたんだけど、このswap関数でちょっと心が揺らいでたり
(変数の概念とかも数学から離れていないと言う意味で、数学+α程度の知識でプログラミングできる言語だと思う)
0447デフォルトの名無しさん
2012/01/29(日) 13:24:16.02Array=配列 ですが、何か
0448デフォルトの名無しさん
2012/01/29(日) 13:24:26.380449デフォルトの名無しさん
2012/01/29(日) 13:26:31.49ん・・・
それって、結局Haskellのやり方と同じことを手続き型言語でもリストのswapの勉強の際には教えるってこと?
0450デフォルトの名無しさん
2012/01/29(日) 13:28:51.88何というか・・・
行間嫁よ
そんなの当たり前だろ
0451デフォルトの名無しさん
2012/01/29(日) 13:31:51.09rubyの場合、リストっぽく使える配列だね
pythonとは名前が逆だけど、実装は何が違うんだろう?
0452デフォルトの名無しさん
2012/01/29(日) 13:36:38.70はあ?文脈読んでないのはオマエだろ。
>>424のリンク先のコードのswap関数の型を書いてみろよ。
どこをどう見たって、リスト/配列中の1組の値のswapだ。
型情報以上に重要な「行間」があるなら書いてみろw
0453デフォルトの名無しさん
2012/01/29(日) 13:45:07.16結果としてHaskellのやり方と同じことを初心者には教えることになるが、
そんなことが言いたかったのではないんだ
・一般的にリストと呼ばれている構造をプログラムで表現する方法
・その表現方法の上での、リストに関する様々な演算方法
リスト処理を初心者に教える入門書はこの2点を分かってもらいたくて書いている
Haskell でのプリミティブなリストの表現方法はいわゆる前方参照の単方向リストだが、
概念は他言語で表現されたリストと似ているし、表現方法が同じなら同じ方法が使える
もし swap 処理を教えるとしたら、その概念に沿って教えるのが自然だ
概念から外れた方法を理解させようとしている入門書があるなら、
その入門書は(少なくともその部分に関しては)クソだと思う
0454デフォルトの名無しさん
2012/01/29(日) 14:12:10.92視野が狭いな・・・
0455デフォルトの名無しさん
2012/01/29(日) 14:25:57.63リスト専門の入門書ってのは読んだこと無いんだが、もし在るならそうなるだろうね
Haskellでちょっと不便かな?と思ったのは配列も値が変えられないだろうという事。結局、IOモナドなり、Stateモナドなりを頼る事になりそうなのがね・・・
>>425のupdate関数は初心者にも作れるし、意外と有効かも
(全体を2回書き換える事にはなるが、コード上は交換したい値を一つずつ更新してるのは、初心者には分かりやすそう)
最近はリストなんだか配列なんだかという、(コード上の)データ構造の性質がハッキリしない言語が多くなってきたから、楽にはなったけど、データ構造の性質を教えるのにはちょっと不便になってきた気がする
(そう言う意味では、Cとかの方が生々しい意味で最適なのかも知れないが、生々しすぎて初心者には敷居が高いし・・・)
0456453
2012/01/29(日) 14:33:26.96読み返したら誤解を与えそうな感じがするから言っておくが
一般的なリストの構造とリストの演算を初心者に教える過程で swap を教えるのなら、
結果としてHaskellのやり方と同じことを教えることになる、という事だからな
要素の破壊的な代入が許されるタイプのリストなら、
普通の変数同士のswapのようにテンポラリ変数を使って比較的素早くswapできるし、
そのように解説している入門書もあるだろうが、それは目的が違う
その部分の関しては、リストの構造とリストの演算を学ばせるためじゃない
(喩えは悪いかもだが、方程式の解法で移項というテクニックを教えるようなもの)
0457453
2012/01/29(日) 14:34:53.970458デフォルトの名無しさん
2012/01/29(日) 14:41:52.19いや、ありがとう
他人に書かれてもドンマイだよ
変数の値が書き換わるのが理解出来ない初心者(かなり稀なパターン)へ手を替え品を替え説明するのに比べれば。。。
変数が箱って言う例えは誰が考えたんだよ。。。
0459453
2012/01/29(日) 14:48:17.90値と変数を束縛して固定するイメージよりは、
値を入れるための箱のイメージの方が先にあったのではないか
と、大して根拠もなく個人的には思ってる
0460デフォルトの名無しさん
2012/01/29(日) 15:00:35.95それは分かる。つーか、自分も似た感覚なんだが、箱の中身がコピーされるとか、新しい値を入れると消えちゃうとかの説明がね。。。
箱じゃ無くて1個のみのスタックみたいなところてん式(追い出された値は捨てられる)の説明でもコピーが説明出来ないしね。。。
まあ、そいつがバカ過ぎなのが問題なんだけど、普通の人はメモリって何?が基準だしなぁ。。。と、基本的な事柄は紙の上で説明出来るのがベストなのかなぁ。。。とか考えてhaskellに流れ着いてたり
ちょっとコンピュータの仕組み齧れば普通の言語の方が自然なんだが。。。
0461453
2012/01/29(日) 15:15:26.29私がC言語を初心者に教えている時は、一般的な「変数=箱」のような喩えではなく、
もう初めから「変数=メモリアドレスの別名」と直に教える
そして、メモリとはどういう構造か、その上でどんな事ができるかを教えてる
当然メモリって何?が基準だけど、C言語ならそこから逃げられないし
喩えると余計に分かりにくい
Haskellを初心者に教えた事は一度しかないけど、
その時も箱とかの喩え話じゃなく、「変数=値の別名」と直に束縛の概念を教えた
0462デフォルトの名無しさん
2012/01/29(日) 15:36:15.61自分も結局、変数=値の別名で教えた
おバカなその人はhaskellも無い頃の思い出だが、cpuの仕組み習ってる筈なのに(情報技術科の同級生)、全く理解出来てなかった
そこまでのバカは捨て置いても良いと思うんだけど、手続き型だとスコープの問題もあるのよね。。。
関数内でswapしたのに値が変わってない!!とか
ガッコの先生じゃ無いから、放っときゃ良いんだけど、なるべくそう言う「?」が無い言語が望ましいんじゃ無いかと
本気でプログラマ目指すなら、多分javaやC#しか使わなくても、Cでメモリの概念を直接覚える必要があるだろうな。とは思う
(C#は限定的でもポインタ残してたのは、本当に英断だった)
0463デフォルトの名無しさん
2012/01/29(日) 18:06:25.05おまえは心が狭いな
素直に自分の間違いを認めればいいのに
0464デフォルトの名無しさん
2012/01/29(日) 19:00:27.451、リストの中身を配列に移す
2、配列で値を交換
3、配列の中身をリストに戻す
って書いてて、値の交換が何度も必要な場面で毎回リストに戻す馬鹿がどこに居るよ
行間嫁ってのは、そう言うこと
そんな応用力無い奴はプログラマになれないだろが
0465デフォルトの名無しさん
2012/01/29(日) 21:03:37.16気になるのはあるね。
swapは、配列の発想から抜け出せないから出てこないだけで、
リストだと思えば、切ってポインタ繋ぎかえるだけじゃんと思いつくと思う。
Haskellだと、こんな感じか。
swap i j l = let
(cs,d:ds) = splitAt j l
(as,b:bs) = splitAt i cs
in as++[d]++bs++[b]++ds
まぁ、swapくらい標準で用意して欲しい気はする。
0466デフォルトの名無しさん
2012/01/29(日) 21:20:50.26綺麗事だけどさ
0467デフォルトの名無しさん
2012/01/29(日) 21:50:07.46swap の需要は圧倒的に少ないわな
正直、今まで必要になった事があったのかどうか思い出せん
0468デフォルトの名無しさん
2012/01/29(日) 22:09:42.45Haskellは、Sort簡単だからあまり出番がないのかも。
でも、Sliceは欲しいな。
■ このスレッドは過去ログ倉庫に格納されています