関数型プログラミング言語Haskell Part21
■ このスレッドは過去ログ倉庫に格納されています
0001デフォルトの名無しさん
2013/01/21(月) 02:16:16.07ttp://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/
Part17 ttp://toro.2ch.net/test/read.cgi/tech/1325510368/
Part18 ttp://toro.2ch.net/test/read.cgi/tech/1331902463/
Part19 ttp://toro.2ch.net/test/read.cgi/tech/1340760070/
Part20 ttp://toro.2ch.net/test/read.cgi/tech/1350428908/
0449デフォルトの名無しさん
2013/03/03(日) 19:06:45.67手続きじゃない部分でもdo記法とか使えるのがMonadクラス
0450デフォルトの名無しさん
2013/03/03(日) 19:26:19.16それは悪かった。そんなつもりはまったくなかった。
しいて言えば、こっちがモナドに馬鹿にされてると感じてるかもしれん
0451デフォルトの名無しさん
2013/03/03(日) 20:30:33.90手続き型を見下してなんかいないよ
手続き型プログラミングと関数型プログラミングの間に存在するパラダイムの壁が認識できていないのではないか、ということだよ
0452デフォルトの名無しさん
2013/03/03(日) 20:42:19.78手続き型はもちろん、モナド込みの関数型でも、どちらのパラダイムも満足
できるものではないと思っている。だからパラダイムとか壁とかという表現も
なんだかなと思うのだ
0453デフォルトの名無しさん
2013/03/03(日) 20:53:23.10パラダイムに満足できるかどうかと、
パラダイムに違いがあるかどうかという事とは、
全く別の事だと思う。
それとも、両者のパラダイムに満足できなければ、
両者のパラダイムにたいした違いは無いという事になるの?
>>443 >>451 は、パラダイムにはっきりとした違いがあるのだから、
一方のパラダイムをもう一方のパラダイムの延長で考えるのではなく、
違いを認識して別物として考えないといけないのではないか、
と言っているのだと思う。
0454デフォルトの名無しさん
2013/03/03(日) 21:40:53.72>両者のパラダイムにたいした違いは無いという事になるの?
うん。第三のパラダイムから見ればそういうことになるね。
モナドだってそう思ってるんじゃないの?
0455デフォルトの名無しさん
2013/03/03(日) 21:42:49.12これに尽きるな。
0456デフォルトの名無しさん
2013/03/03(日) 22:09:28.85満足できるかどうかは個人の主観の問題だよな。
違いがあるかどうかは視点の問題だよな。
前者の結果によって後者が影響されるのはおかしくないか?
0457デフォルトの名無しさん
2013/03/03(日) 23:12:13.13>副作用のある部分と無い部分をキッチリ分離できる
>そんな言語が、副作用のある部分を
>手続き型と同じように書けるんだから
モナドの御利益はこれに尽きるとのことなので、
スマンが、そこが分かるこれぞという例題を一つ教えてもらえんだろうか
0458デフォルトの名無しさん
2013/03/03(日) 23:20:44.85これを
> モナドの御利益はこれに尽きるとのことなので、
こう解釈する時点で、悪意があることがハッキリしたね
0459デフォルトの名無しさん
2013/03/03(日) 23:22:55.65どうしても自分の理解できる範囲で収めたがってるように感じる
0460デフォルトの名無しさん
2013/03/03(日) 23:27:50.120461デフォルトの名無しさん
2013/03/03(日) 23:29:10.07import System.Random
main :: IO ()
main = do
v <- randomIO :: IO Int
let a = double v
print a
double :: Int -> Int
double x = x * 2
main 関数は戻り値が IO () 型で副作用がある。
double 関数は戻り値が Int 型で副作用がない。
副作用がある関数とない関数、それぞれの定義が必然的に明確に分かれる。
(ただし変な事をしない限り)
0462デフォルトの名無しさん
2013/03/03(日) 23:37:32.74とりあえずあんがと
0463デフォルトの名無しさん
2013/03/03(日) 23:45:29.84>副作用がある関数とない関数、それぞれの定義が必然的に明確に分かれる
これだけだとvoidとintの区別と同じだねと思うよね。もちろん悪意なんかないよ
0464デフォルトの名無しさん
2013/03/03(日) 23:51:38.96もちろん悪意なんてないよ
0465デフォルトの名無しさん
2013/03/03(日) 23:52:05.09> voidとintの区別と同じ
もっと詳しく説明していただけないでしょうか。
できるだけ例を分かりやすく改善させたいと思います。
Int 型を戻り値とする関数の中で
副作用がある処理はできないという事を簡単な例で示したつもりです。
C 言語の int 型を戻り値とする関数では、
中で printf 関数を呼べたりできるので、
Haskell のものとは全く違うと思うのですが。
0466デフォルトの名無しさん
2013/03/04(月) 00:21:37.530467デフォルトの名無しさん
2013/03/04(月) 00:55:52.99流石にアホすぎるわ
説明求める前に入門書でも読めよ
0468デフォルトの名無しさん
2013/03/04(月) 01:02:54.47何が「できない」か説明したくなるのは静的型だから当然ではあるけど
やっぱり何が「できる」かを堂々と言える動的型を先に習得して
その後でHaskellをやった方が話が早いんじゃないかと思う
0469デフォルトの名無しさん
2013/03/04(月) 01:06:52.58それとも静的型なら再代入ができなくなるのか
0470デフォルトの名無しさん
2013/03/04(月) 01:38:35.270471デフォルトの名無しさん
2013/03/04(月) 03:15:23.070472デフォルトの名無しさん
2013/03/04(月) 07:01:52.07>Int 型を戻り値とする関数の中で
>副作用がある処理はできないという事
なるほど、これは分かる。関数型だからね。
しかしそれなら、Cでもコンパイラでチェックしようとすればできることだ。
むしろmainの方が本質的なのか?
0473デフォルトの名無しさん
2013/03/04(月) 07:02:55.62>>457 で求められたのは次の要素を含む例でした。
>副作用のある部分と無い部分をキッチリ分離できる
>そんな言語が、副作用のある部分を
>手続き型と同じように書けるんだから
まず、関数 double 内では副作用がある処理はできないことで、
副作用のある部分と無い部分をキッチリ分離「できる」事を示しています。
そして、main 関数の中で副作用がある処理を
手続き型と同じように「書ける」事を示しています。
「できる」「書ける」ことを例として示しましたが、
分かりづらければ、具体的に何処が分からなかったか指摘してください。
改善します。
0474デフォルトの名無しさん
2013/03/04(月) 07:04:20.32コンパイラ依存の話をしているのではなく、
言語としての仕様の話をしているのだと思っていました。
それは私の勘違いでしょうか。
0475デフォルトの名無しさん
2013/03/04(月) 07:30:32.05Cコンパイラは次の関数ポインタを受け取る関数
int twice(int (*f)(int), int x) {
return f(f(x));
}
が副作用があるか無いかを、どうやって知れば良いの?
渡される関数ポインタfがどんなものか分からないのに。
それとも、関数ポインタが渡されるときは、常に副作用があると考えるの?
なお、Haskellの場合は、副作用の無い関数として定義できるよ。
twice :: (Int -> Int) -> Int -> Int
twice f = f . f
0476デフォルトの名無しさん
2013/03/04(月) 08:29:51.070477デフォルトの名無しさん
2013/03/04(月) 08:35:33.680478デフォルトの名無しさん
2013/03/04(月) 08:39:28.49お前らスレの流れも追えないのか
0479デフォルトの名無しさん
2013/03/04(月) 09:40:58.03> double :: Int -> Int
> double x = x * 2
これを
> 関数 double 内では副作用がある処理はできない
こう説明されても、なぜできないのかサッパリ分からんぞ?
0480デフォルトの名無しさん
2013/03/04(月) 10:50:47.04そもそもHaskellは、副作用のある関数を書くことが文法上できないのだから
0481デフォルトの名無しさん
2013/03/04(月) 10:56:46.980482デフォルトの名無しさん
2013/03/04(月) 11:00:29.57できない理由として考えられる物は二つ
・わざとできないように公理系を作ったから
・公理をいくら変えてもできないものはできないから
後者は科学
前者は科学ではないかも
0483デフォルトの名無しさん
2013/03/04(月) 11:12:37.520484デフォルトの名無しさん
2013/03/04(月) 11:17:51.630485デフォルトの名無しさん
2013/03/04(月) 11:36:27.90世間一般でいう副作用って、本来は不要なものってイメージがあるから。
0486デフォルトの名無しさん
2013/03/04(月) 11:49:11.42言語によっては、GCを強制的に掛けることができるものがある。
時系列 t1, t2 を考えて、強制GCの応答速度が t1,t2で異なるとすると、
ほとんどの計算に副作用があることになる。
0487デフォルトの名無しさん
2013/03/04(月) 11:49:38.54世間一般の用語とは別に、意味がある術語だから。
0488デフォルトの名無しさん
2013/03/04(月) 11:50:12.12GCと副作用関係なくね?
0489デフォルトの名無しさん
2013/03/04(月) 11:52:56.510490デフォルトの名無しさん
2013/03/04(月) 11:53:12.11少なくとも>>485はReturn 以外に何かプログラマに影響を与えるものが
残されるのが副作用という解釈のように読めたから。
0491デフォルトの名無しさん
2013/03/04(月) 12:04:41.81そんな脊髄反射レスするほど悔しかったのか……
0492デフォルトの名無しさん
2013/03/04(月) 12:10:01.00うぜぇ
0493デフォルトの名無しさん
2013/03/04(月) 12:14:19.560494デフォルトの名無しさん
2013/03/04(月) 12:17:36.04>>485は功利的な価値のあるものが主作用であって、副作用と呼ばれて
いるものが主作用なのではないの?と訊いている。
0495デフォルトの名無しさん
2013/03/04(月) 12:20:33.940496デフォルトの名無しさん
2013/03/04(月) 12:22:38.05関数の主作用は関数の戻値
戻値以外に何か意味のある作用があればそれが関数の副作用
0497デフォルトの名無しさん
2013/03/04(月) 12:25:51.49やたら偉そうに質問してくるのが凄いよな
0498デフォルトの名無しさん
2013/03/04(月) 12:32:10.99そうだよ。だから最後の「なにか意味のある」を引き出したくて、
>>486を書いたんだ。
0499498
2013/03/04(月) 12:33:47.600500デフォルトの名無しさん
2013/03/04(月) 12:33:53.28そこで静的型が関係してくる
returnする型を静的に宣言したり解析したりするから主作用
そういうことをしてない方が副作用
してない方が主になったら静的型が衰退するから
0501デフォルトの名無しさん
2013/03/04(月) 12:40:21.800502デフォルトの名無しさん
2013/03/04(月) 12:42:31.240503デフォルトの名無しさん
2013/03/04(月) 12:47:06.02まあ待て、まだ自演説が残されている
0504デフォルトの名無しさん
2013/03/04(月) 12:50:53.77letとかでIOの関数定義したとしてもただの定義だから動かないからin以降でその関数呼び出すことになる
結局元の関数の型はIOになる
0505デフォルトの名無しさん
2013/03/04(月) 13:13:43.30副作用のある部分と無い部分をキッチリ分離できるというモナドの特性を否定するために、
副作用について議論をしたいと思います
0506デフォルトの名無しさん
2013/03/04(月) 13:26:33.54自然は不変だが不自然は変化しやすいので気をつけよう
0507デフォルトの名無しさん
2013/03/04(月) 13:32:04.44突然「お前は副作用を理解してない」とか言い出すやつが来たから
0509デフォルトの名無しさん
2013/03/04(月) 14:23:47.280510デフォルトの名無しさん
2013/03/04(月) 14:39:07.140511デフォルトの名無しさん
2013/03/04(月) 14:42:25.730512デフォルトの名無しさん
2013/03/04(月) 14:43:58.290513デフォルトの名無しさん
2013/03/04(月) 14:52:27.78具象化する際にいろんな仕組みを多重的に組み込める
0514デフォルトの名無しさん
2013/03/04(月) 15:05:01.66IO以外のモナドは、演算子オーバーロードで手続きのように見えるだけ
0515デフォルトの名無しさん
2013/03/04(月) 15:07:51.870516デフォルトの名無しさん
2013/03/04(月) 15:19:13.100517デフォルトの名無しさん
2013/03/04(月) 15:26:13.030518デフォルトの名無しさん
2013/03/04(月) 15:50:28.23>>510
それはモサドやろが!
0519デフォルトの名無しさん
2013/03/04(月) 17:23:56.540520デフォルトの名無しさん
2013/03/04(月) 20:01:38.17C言語を、ソースコードと実行ファイルを結び付ける関数とすれば、そこには副作用はない。
0521デフォルトの名無しさん
2013/03/04(月) 20:03:41.880522デフォルトの名無しさん
2013/03/04(月) 20:09:16.91だから、それは副作用をどう定義するかによる。
と今までいくつかのレスで言われていますが、見ていませんか?
あなたの定義ではC言語にも副作用はないと言える。
しかし別の定義ではそれは成り立たない場合もある。
普通、「Haskell は副作用のある部分とない部分を明確に分ける」
と言った場合の副作用は、たいていのHaskellプログラマの共通認識として、
C言語にも副作用はないとは言えないような定義だと思う。
0523デフォルトの名無しさん
2013/03/04(月) 20:16:13.53期待を裏切るというか期待と無関係な副作用が問題になる
期待がなければ主作用も副作用もない
0524デフォルトの名無しさん
2013/03/04(月) 20:24:15.20http://en.wikipedia.org/wiki/Side_effect_%28computer_science%29
Haskell のプログラミングという文脈で副作用といった場合は、
普通はこれを指します。
0525デフォルトの名無しさん
2013/03/04(月) 20:45:42.34副作用という言葉について、よほど恣意的で狭い定義を作らない限りは。
でも「参照透過性」なら、切り分けられるだろう。
0526デフォルトの名無しさん
2013/03/04(月) 21:05:55.56>まず、関数 double 内では副作用がある処理はできない
これはgoodだが、Cでもできる(モナド固有の利点ではない)と472で言った。
>副作用がある処理を手続き型と同じように「書ける」
これももちろん、Cでもできる。
結局、どちらもCでもできることだがなあ、というのが現時点での感想。
どうなの?
>>474
>コンパイラ依存の話をしているのではなく、
>言語としての仕様の話をしているのだと
うん。言語としての仕様の話でいいです。
コンパイラ依存の話をしたつもりはないんだが。
0527デフォルトの名無しさん
2013/03/04(月) 21:10:07.17>これはgoodだが、Cでもできる(モナド固有の利点ではない)と472で言った。
(正)これはgoodだが、Cでも、できないようにできる(モナド固有の利点ではない)と472で言った。
0528デフォルトの名無しさん
2013/03/04(月) 21:19:21.75>>475のC言語のコードで副作用のある関数を渡したら
コンパイルエラーになる(警告でもいい)コンパイラを教えてくれ
無いなら、CでHaskellと同じことはできてない
0529デフォルトの名無しさん
2013/03/04(月) 21:32:39.33たぶん、私のレスが勘違いをさせた原因なのでしょう、申し訳ないです。
Haskellでしかできない事だ、とは私は言っていないんです。
副作用のある処理、特に IO 処理をHaskellで表現する際に、
Haskellの利点(型安全、遅延評価、純粋性など)を
できる限り壊さず、かつ使いやすい方法は無いかと模索していたところで
モナドのアイデアを閃いたのが、もともとの発端だったと思います。
閃いたというよりは、出会ったと言った方がより正確ですが。
この辺りの経緯は、論文「A History of Haskell」に少し載っています。
ですが、考えてみてください。
副作用のある処理って、C言語ではできないのでしょうか。
Haskell の特徴なのでしょうか。
違いますよね、むしろC言語なら「普通にできる」事です。
副作用は、実用的なアプリケーションを作るのにまず間違いなく必要なものです。
Haskellは実用的になるように目指した言語なので(上記論文参照)、
Haskellでも「手続き型言語のように」副作用が絶対に必要です。
それを、Haskellの利点を壊さないように取り入れるのに使ったアイデアがモナドです。
モナドのアイデアが採用される前は別の方法でIO処理をしていました(上記論文参照)
したがって、C言語でもできるよね、と感じるのはむしろ当たり前です。
C言語でできる事をHaskellでも、といって取り入れた機能なのですから。
だから本当は、副作用のある処理ができる事がモナドの特徴なのではなくて、
副作用のある処理が「Haskellの良さを壊さずに」できることが特徴なのです。
副作用の部分をきっちり分けることでHaskelの良さを壊さない、
型システムになじませることでHaskelの良さを壊さない、ということです。
0530デフォルトの名無しさん
2013/03/04(月) 21:59:42.46>だから本当は、副作用のある処理ができる事がモナドの特徴なのではなくて、
>副作用のある処理が「Haskellの良さを壊さずに」できることが特徴なのです。
はい。そうなのだろうと思います。それは分かります。
>副作用の部分をきっちり分けることでHaskelの良さを壊さない、
副作用の部分を分けることは、Cの場合でもvoidとintなどの区別でできると
前に言いました。「きっちり」というところがHaskellとCとで違うという
ことでしょうか?しかし少なくとも先のdoubleの例題ではそんなに違いは
見えないのですが。
>型システムになじませることでHaskelの良さを壊さない、ということです。
この点も(たぶん)分かってると思います。
0531デフォルトの名無しさん
2013/03/04(月) 22:09:30.20Haskellは参照透過な形で副作用を含む処理を表現できるけれども、
C言語では、ほとんどの場合、参照透過な形では表現できない。ってところでは?
529ではないけれど。
0532デフォルトの名無しさん
2013/03/04(月) 22:10:43.57おもしろい例題なので返答を考えていた所だったが時間がないので
そのうちにということにしてくれ。すまん。
ただこの例題は、もとのモナドの問題と直接関係ないと思うし、
現実のCと比べることもあんまり意味はないと思う。
ポインタというのもなんだかなだし。今日はそんなところだ。
0533デフォルトの名無しさん
2013/03/04(月) 22:18:02.78>Haskellは参照透過な形で副作用を含む処理を表現できるけれども
ごめん。それが分からんのだ。
なにかこれぞというプログラム例はある?
doubleの例がそれかい?
0534デフォルトの名無しさん
2013/03/04(月) 22:19:56.81ポインタが出てくるのは、Haskellのクロージャに近いものが
Cでは関数ポインタしか無いからだし、
間違って副作用のある関数を渡せないという例なんだから
副作用のある部分とない部分を明確に分けるという話に直接繋がってるよ
0535デフォルトの名無しさん
2013/03/04(月) 22:22:33.09横レスだけど少しはモナドでググって知識を付けてから質問したらいいと思いました
0536デフォルトの名無しさん
2013/03/04(月) 22:27:06.980537デフォルトの名無しさん
2013/03/04(月) 22:27:07.99Haskellだったらそんなものはそもそもコンパイルが通らない(から安全)
って話じゃないの?
0538デフォルトの名無しさん
2013/03/04(月) 22:43:10.55それ以外はunsafePerformIOを適用しないこと
このルールをコンパイラが保証できるか?
暗黙のルールをこっそりと保証するにはどうすればいいのか
0539デフォルトの名無しさん
2013/03/04(月) 22:44:47.740540デフォルトの名無しさん
2013/03/04(月) 22:48:42.180541デフォルトの名無しさん
2013/03/04(月) 22:49:18.35この人質問するのはいいけど全然自分で調べようとしないから話が進まないにも程がある
0542デフォルトの名無しさん
2013/03/04(月) 22:51:21.15それがマシンパワーの弱かった時代のCとUNIXの哲学だからな。
ところが本物のアホは今やそれがアホげた志向だと気づく事が出来ない。
こういうアホはそのうち今のCOBOLとコボラー並に邪魔ものになるよ。
0543デフォルトの名無しさん
2013/03/04(月) 22:55:03.820544デフォルトの名無しさん
2013/03/04(月) 23:24:24.15きっちりなんて曖昧でしたね、すいません。
「きっちり分けられる = 関数単位で分けられる」 です。
Haskell のプログラムの基本単位は関数です。
Haskell の言語仕様では関数単位で副作用の有無が定まります。
ステートメント単位とか、命令単位とか、行単位とかではなくて、
関数単位です。
戻り値が IO a 型ではない関数は、絶対に副作用はありません。
(本当は例外があるのですが、話がややこしくなるので今は考えません)
しかし、ほんの少しでも副作用をさせたいのなら、
その関数は IO a 型の値を戻さないといけません。
ほんの少しであっても、「その関数自体が副作用がある」と見なされます。
逆に IO a 型を戻す関数は、副作用があるかどうかは、
実はその関数の定義(中身)を見なければ明らかにはなりません。
ですが、この関数は中に副作用がある処理を含めることが「可能」なので、
IO a 型を戻す関数を内部に含む関数も IO b 型の値を戻すと決められています。
これらは言語仕様です。
プログラマが注意してそのように書くとこで安全性が保たれる、
というレベルの話ではなく、そうしなければコンパイルできないというレベルです。
(>>537)
コンパイラは関数の戻り値の型によって、
副作用が絶対に無い関数か、副作用がある可能性がある関数かを見分けます。
そして、ここが大事ですが、プログラマもコンパイルが通るように、
副作用がある関数か、副作用がない関数かをしっかり意識して分けます。
(初心者にとっては、分けざるを得ないという認識でしょうか)
0545デフォルトの名無しさん
2013/03/04(月) 23:42:07.28C言語でも分けられると言いますが、実際のところ、
Haskellのようにしっかり分けるCプログラマはまずいないでしょう。
実行効率やプログラムソースの読みやすさなど、理由はいくつかあります。
やろうと思えば分けられる言語と、分けることが前提の言語では全く違うと思います。
この辺りは、C vs C++ におけるオブジェクト指向と似てるかも知れません。
0546デフォルトの名無しさん
2013/03/04(月) 23:52:28.17CでOOPできないと主張するために、OOPの必須条件が次々と追加されたよね
0547デフォルトの名無しさん
2013/03/05(火) 00:26:28.70じゃなくて
haskellでは副作用がある部分とない部分を区別しないと書けません
だろ
できることじゃなくてできないことに意味がある
カプセル化みたいなもん
0548デフォルトの名無しさん
2013/03/05(火) 00:45:39.99■ このスレッドは過去ログ倉庫に格納されています