トップページtech
1001コメント316KB

関数型プログラミング言語Haskell Part21

■ このスレッドは過去ログ倉庫に格納されています
0001デフォルトの名無しさん2013/01/21(月) 02:16:16.07
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/
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
手続き型と同じように書けるのはIO型
手続きじゃない部分でもdo記法とか使えるのがMonadクラス
0450デフォルトの名無しさん2013/03/03(日) 19:26:19.16
>>448
それは悪かった。そんなつもりはまったくなかった。
しいて言えば、こっちがモナドに馬鹿にされてると感じてるかもしれん
0451デフォルトの名無しさん2013/03/03(日) 20:30:33.90
>>446
手続き型を見下してなんかいないよ
手続き型プログラミングと関数型プログラミングの間に存在するパラダイムの壁が認識できていないのではないか、ということだよ
0452デフォルトの名無しさん2013/03/03(日) 20:42:19.78
>>451
手続き型はもちろん、モナド込みの関数型でも、どちらのパラダイムも満足
できるものではないと思っている。だからパラダイムとか壁とかという表現も
なんだかなと思うのだ
0453デフォルトの名無しさん2013/03/03(日) 20:53:23.10
>>452
パラダイムに満足できるかどうかと、
パラダイムに違いがあるかどうかという事とは、
全く別の事だと思う。

それとも、両者のパラダイムに満足できなければ、
両者のパラダイムにたいした違いは無いという事になるの?

>>443 >>451 は、パラダイムにはっきりとした違いがあるのだから、
一方のパラダイムをもう一方のパラダイムの延長で考えるのではなく、
違いを認識して別物として考えないといけないのではないか、
と言っているのだと思う。
0454デフォルトの名無しさん2013/03/03(日) 21:40:53.72
>それとも、両者のパラダイムに満足できなければ、
>両者のパラダイムにたいした違いは無いという事になるの?

うん。第三のパラダイムから見ればそういうことになるね。
モナドだってそう思ってるんじゃないの?
0455デフォルトの名無しさん2013/03/03(日) 21:42:49.12
>>447
これに尽きるな。
0456デフォルトの名無しさん2013/03/03(日) 22:09:28.85
>>454
満足できるかどうかは個人の主観の問題だよな。
違いがあるかどうかは視点の問題だよな。

前者の結果によって後者が影響されるのはおかしくないか?
0457デフォルトの名無しさん2013/03/03(日) 23:12:13.13
>>447 >>455
>副作用のある部分と無い部分をキッチリ分離できる
>そんな言語が、副作用のある部分を
>手続き型と同じように書けるんだから

モナドの御利益はこれに尽きるとのことなので、
スマンが、そこが分かるこれぞという例題を一つ教えてもらえんだろうか
0458デフォルトの名無しさん2013/03/03(日) 23:20:44.85
> それだけで御利益あるだろ

これを

> モナドの御利益はこれに尽きるとのことなので、

こう解釈する時点で、悪意があることがハッキリしたね
0459デフォルトの名無しさん2013/03/03(日) 23:22:55.65
頭が悪いだけかもしれん
どうしても自分の理解できる範囲で収めたがってるように感じる
0460デフォルトの名無しさん2013/03/03(日) 23:27:50.12
悪意はないよ
0461デフォルトの名無しさん2013/03/03(日) 23:29:10.07
>>457
import 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
>>461
とりあえずあんがと
0463デフォルトの名無しさん2013/03/03(日) 23:45:29.84
>>461
>副作用がある関数とない関数、それぞれの定義が必然的に明確に分かれる
これだけだとvoidとintの区別と同じだねと思うよね。もちろん悪意なんかないよ
0464デフォルトの名無しさん2013/03/03(日) 23:51:38.96
え?馬鹿?

もちろん悪意なんてないよ
0465デフォルトの名無しさん2013/03/03(日) 23:52:05.09
>>463
> voidとintの区別と同じ

もっと詳しく説明していただけないでしょうか。
できるだけ例を分かりやすく改善させたいと思います。

Int 型を戻り値とする関数の中で
副作用がある処理はできないという事を簡単な例で示したつもりです。

C 言語の int 型を戻り値とする関数では、
中で printf 関数を呼べたりできるので、
Haskell のものとは全く違うと思うのですが。
0466デフォルトの名無しさん2013/03/04(月) 00:21:37.53
Haskell Report 2010 読めば良い。
0467デフォルトの名無しさん2013/03/04(月) 00:55:52.99
>voidとintの区別と同じ
流石にアホすぎるわ
説明求める前に入門書でも読めよ
0468デフォルトの名無しさん2013/03/04(月) 01:02:54.47
>副作用がある処理はできないという事を簡単な例で示したつもりです。

何が「できない」か説明したくなるのは静的型だから当然ではあるけど
やっぱり何が「できる」かを堂々と言える動的型を先に習得して
その後でHaskellをやった方が話が早いんじゃないかと思う
0469デフォルトの名無しさん2013/03/04(月) 01:06:52.58
動的型だの静的型だのは副作用と関係ねーよ
それとも静的型なら再代入ができなくなるのか
0470デフォルトの名無しさん2013/03/04(月) 01:38:35.27
無駄にプライドの高い中学生みたいな手続き脳&スパゲッティ脳が居る
0471デフォルトの名無しさん2013/03/04(月) 03:15:23.07
perl忍者最近見ないな
0472デフォルトの名無しさん2013/03/04(月) 07:01:52.07
>>465
>Int 型を戻り値とする関数の中で
>副作用がある処理はできないという事

なるほど、これは分かる。関数型だからね。
しかしそれなら、Cでもコンパイラでチェックしようとすればできることだ。
むしろmainの方が本質的なのか?
0473デフォルトの名無しさん2013/03/04(月) 07:02:55.62
>>468

>>457 で求められたのは次の要素を含む例でした。

>副作用のある部分と無い部分をキッチリ分離できる
>そんな言語が、副作用のある部分を
>手続き型と同じように書けるんだから

まず、関数 double 内では副作用がある処理はできないことで、
副作用のある部分と無い部分をキッチリ分離「できる」事を示しています。

そして、main 関数の中で副作用がある処理を
手続き型と同じように「書ける」事を示しています。

「できる」「書ける」ことを例として示しましたが、
分かりづらければ、具体的に何処が分からなかったか指摘してください。
改善します。
0474デフォルトの名無しさん2013/03/04(月) 07:04:20.32
>>472
コンパイラ依存の話をしているのではなく、
言語としての仕様の話をしているのだと思っていました。

それは私の勘違いでしょうか。
0475デフォルトの名無しさん2013/03/04(月) 07:30:32.05
>>472
Cコンパイラは次の関数ポインタを受け取る関数

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.07
Haskellのコンパイラは副作用の有無をどうやって知るの?
0477デフォルトの名無しさん2013/03/04(月) 08:35:33.68
知るも何も、Haskellに副作用は存在しないから
0478デフォルトの名無しさん2013/03/04(月) 08:39:28.49
>>476-477
お前らスレの流れも追えないのか
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.98
元々「副作用」って言葉に明確な定義なんてないだろ。アホか
0482デフォルトの名無しさん2013/03/04(月) 11:00:29.57
>>479
できない理由として考えられる物は二つ
・わざとできないように公理系を作ったから
・公理をいくら変えてもできないものはできないから
後者は科学
前者は科学ではないかも
0483デフォルトの名無しさん2013/03/04(月) 11:12:37.52
流れ全く読まずにドヤ顔レスするやつが定期的に湧くね、このスレ
0484デフォルトの名無しさん2013/03/04(月) 11:17:51.63
↑ドヤ顔レスの一例です
0485デフォルトの名無しさん2013/03/04(月) 11:36:27.90
例えば画面への出力を副作用と呼ぶなら、その時に”副作用でない”、意味のある処理って何?って話だな。
世間一般でいう副作用って、本来は不要なものってイメージがあるから。
0486デフォルトの名無しさん2013/03/04(月) 11:49:11.42
>>485
言語によっては、GCを強制的に掛けることができるものがある。
時系列 t1, t2 を考えて、強制GCの応答速度が t1,t2で異なるとすると、
ほとんどの計算に副作用があることになる。
0487デフォルトの名無しさん2013/03/04(月) 11:49:38.54
プログラミング言語の文脈では、たとえばCの規格の用語である「副作用完了点」のように、
世間一般の用語とは別に、意味がある術語だから。
0488デフォルトの名無しさん2013/03/04(月) 11:50:12.12
>>486
GCと副作用関係なくね?
0489デフォルトの名無しさん2013/03/04(月) 11:52:56.51
関係ないことを証明せよ
0490デフォルトの名無しさん2013/03/04(月) 11:53:12.11
>>488
少なくとも>>485はReturn 以外に何かプログラマに影響を与えるものが
残されるのが副作用という解釈のように読めたから。
0491デフォルトの名無しさん2013/03/04(月) 12:04:41.81
>>484
そんな脊髄反射レスするほど悔しかったのか……
0492デフォルトの名無しさん2013/03/04(月) 12:10:01.00
>>491
うぜぇ
0493デフォルトの名無しさん2013/03/04(月) 12:14:19.56
お前らが何について話したいのか全く分からん
0494デフォルトの名無しさん2013/03/04(月) 12:17:36.04
>>493
>>485は功利的な価値のあるものが主作用であって、副作用と呼ばれて
いるものが主作用なのではないの?と訊いている。
0495デフォルトの名無しさん2013/03/04(月) 12:20:33.94
その答えは >>487 で出てる
0496デフォルトの名無しさん2013/03/04(月) 12:22:38.05
関数の副作用について話してるんじゃないのか?
関数の主作用は関数の戻値
戻値以外に何か意味のある作用があればそれが関数の副作用
0497デフォルトの名無しさん2013/03/04(月) 12:25:51.49
このおっさん副作用も知らんで
やたら偉そうに質問してくるのが凄いよな
0498デフォルトの名無しさん2013/03/04(月) 12:32:10.99
>>496
そうだよ。だから最後の「なにか意味のある」を引き出したくて、
>>486を書いたんだ。
04994982013/03/04(月) 12:33:47.60
ごめん。「何か意味のある」だった。
0500デフォルトの名無しさん2013/03/04(月) 12:33:53.28
>>494
そこで静的型が関係してくる
returnする型を静的に宣言したり解析したりするから主作用
そういうことをしてない方が副作用
してない方が主になったら静的型が衰退するから
0501デフォルトの名無しさん2013/03/04(月) 12:40:21.80
副作用の定義なんか誰も聞いてないのに、どうしてこうなった?
0502デフォルトの名無しさん2013/03/04(月) 12:42:31.24
わかったぞw頭のおかしい奴が2匹いるw
0503デフォルトの名無しさん2013/03/04(月) 12:47:06.02
>>502
まあ待て、まだ自演説が残されている
0504デフォルトの名無しさん2013/03/04(月) 12:50:53.77
最後に返す型がIOじゃないと作用しないんじゃね
letとかでIOの関数定義したとしてもただの定義だから動かないからin以降でその関数呼び出すことになる
結局元の関数の型はIOになる
0505デフォルトの名無しさん2013/03/04(月) 13:13:43.30
Haskellのモナドが意味無いものという結論が欲しいので、
副作用のある部分と無い部分をキッチリ分離できるというモナドの特性を否定するために、
副作用について議論をしたいと思います
0506デフォルトの名無しさん2013/03/04(月) 13:26:33.54
いや、意味はあるが意味を求めた代償として不自然になる
自然は不変だが不自然は変化しやすいので気をつけよう
0507デフォルトの名無しさん2013/03/04(月) 13:32:04.44
>>501
突然「お前は副作用を理解してない」とか言い出すやつが来たから
05084932013/03/04(月) 13:41:19.16
>>505
なるほど理解できた、ありがとう
0509デフォルトの名無しさん2013/03/04(月) 14:23:47.28
で、結局モナドてなんなの?
0510デフォルトの名無しさん2013/03/04(月) 14:39:07.14
暗殺集団だろ
0511デフォルトの名無しさん2013/03/04(月) 14:42:25.73
IOを中心とする型の集合
0512デフォルトの名無しさん2013/03/04(月) 14:43:58.29
自己関手の圏のモノイド対象
0513デフォルトの名無しさん2013/03/04(月) 14:52:27.78
手続き処理を記述するための汎用性の高い抽象クラス
具象化する際にいろんな仕組みを多重的に組み込める
0514デフォルトの名無しさん2013/03/04(月) 15:05:01.66
手続きはIOだけ
IO以外のモナドは、演算子オーバーロードで手続きのように見えるだけ
0515デフォルトの名無しさん2013/03/04(月) 15:07:51.87
m>>=fのfが手続き的に順番に評価されていくのがすべてのモナドで基本じゃないの?
0516デフォルトの名無しさん2013/03/04(月) 15:19:13.10
Monadは型クラスで、型クラスはオーバーロードしかしないよ
0517デフォルトの名無しさん2013/03/04(月) 15:26:13.03
それがどうした
0518デフォルトの名無しさん2013/03/04(月) 15:50:28.23
誰も突っ込んであげなかったようなので僕が処理しときますね

>>510
それはモサドやろが!
0519デフォルトの名無しさん2013/03/04(月) 17:23:56.54
518の優しさに泣いた
0520デフォルトの名無しさん2013/03/04(月) 20:01:38.17
Haskellに副作用がないなら、C言語にも副作用はないといえるのでは?
C言語を、ソースコードと実行ファイルを結び付ける関数とすれば、そこには副作用はない。
0521デフォルトの名無しさん2013/03/04(月) 20:03:41.88
eval は Env と f を引数に取る。 eval の後に Env が変化するとき、それを副作用と呼ぶ。
0522デフォルトの名無しさん2013/03/04(月) 20:09:16.91
>>520
だから、それは副作用をどう定義するかによる。
と今までいくつかのレスで言われていますが、見ていませんか?

あなたの定義ではC言語にも副作用はないと言える。
しかし別の定義ではそれは成り立たない場合もある。

普通、「Haskell は副作用のある部分とない部分を明確に分ける」
と言った場合の副作用は、たいていのHaskellプログラマの共通認識として、
C言語にも副作用はないとは言えないような定義だと思う。
0523デフォルトの名無しさん2013/03/04(月) 20:16:13.53
ある結果 (型など) を期待した時に
期待を裏切るというか期待と無関係な副作用が問題になる
期待がなければ主作用も副作用もない
0524デフォルトの名無しさん2013/03/04(月) 20:24:15.20
コンピュータ・サイエンスにおける副作用
http://en.wikipedia.org/wiki/Side_effect_%28computer_science%29

Haskell のプログラミングという文脈で副作用といった場合は、
普通はこれを指します。
0525デフォルトの名無しさん2013/03/04(月) 20:45:42.34
副作用の有無で、Haskellと、C言語などの他の言語を切り分けるのは難しいと思うよ。
副作用という言葉について、よほど恣意的で狭い定義を作らない限りは。

でも「参照透過性」なら、切り分けられるだろう。
0526デフォルトの名無しさん2013/03/04(月) 21:05:55.56
>>473  遅くなったがありがと

>まず、関数 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
>>526
>>475のC言語のコードで副作用のある関数を渡したら
コンパイルエラーになる(警告でもいい)コンパイラを教えてくれ
無いなら、CでHaskellと同じことはできてない
0529デフォルトの名無しさん2013/03/04(月) 21:32:39.33
>>526
たぶん、私のレスが勘違いをさせた原因なのでしょう、申し訳ないです。
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
>>529 丁寧な説明ありがとう

>だから本当は、副作用のある処理ができる事がモナドの特徴なのではなくて、
>副作用のある処理が「Haskellの良さを壊さずに」できることが特徴なのです。

はい。そうなのだろうと思います。それは分かります。

>副作用の部分をきっちり分けることでHaskelの良さを壊さない、

副作用の部分を分けることは、Cの場合でもvoidとintなどの区別でできると
前に言いました。「きっちり」というところがHaskellとCとで違うという
ことでしょうか?しかし少なくとも先のdoubleの例題ではそんなに違いは
見えないのですが。

>型システムになじませることでHaskelの良さを壊さない、ということです。
この点も(たぶん)分かってると思います。
0531デフォルトの名無しさん2013/03/04(月) 22:09:30.20
>>530
Haskellは参照透過な形で副作用を含む処理を表現できるけれども、
C言語では、ほとんどの場合、参照透過な形では表現できない。ってところでは?

529ではないけれど。
0532デフォルトの名無しさん2013/03/04(月) 22:10:43.57
>>528
おもしろい例題なので返答を考えていた所だったが時間がないので
そのうちにということにしてくれ。すまん。
ただこの例題は、もとのモナドの問題と直接関係ないと思うし、
現実のCと比べることもあんまり意味はないと思う。
ポインタというのもなんだかなだし。今日はそんなところだ。
0533デフォルトの名無しさん2013/03/04(月) 22:18:02.78
>>531 コメントありがと

>Haskellは参照透過な形で副作用を含む処理を表現できるけれども

ごめん。それが分からんのだ。
なにかこれぞというプログラム例はある?
doubleの例がそれかい?
0534デフォルトの名無しさん2013/03/04(月) 22:19:56.81
>>532
ポインタが出てくるのは、Haskellのクロージャに近いものが
Cでは関数ポインタしか無いからだし、
間違って副作用のある関数を渡せないという例なんだから
副作用のある部分とない部分を明確に分けるという話に直接繋がってるよ
0535デフォルトの名無しさん2013/03/04(月) 22:22:33.09
>>533
横レスだけど少しはモナドでググって知識を付けてから質問したらいいと思いました
0536デフォルトの名無しさん2013/03/04(月) 22:27:06.98
このおっさん都合の悪いレスは全部無視するから無駄だと思うぞ
0537デフォルトの名無しさん2013/03/04(月) 22:27:07.99
Cだったら副作用のある関数を「書こうと思えば書けてしまう」けど,
Haskellだったらそんなものはそもそもコンパイルが通らない(から安全)
って話じゃないの?
0538デフォルトの名無しさん2013/03/04(月) 22:43:10.55
mainに一回だけunsafePerformIOを適用すること
それ以外はunsafePerformIOを適用しないこと

このルールをコンパイラが保証できるか?
暗黙のルールをこっそりと保証するにはどうすればいいのか
0539デフォルトの名無しさん2013/03/04(月) 22:44:47.74
Cに副作用がないとか言ってる奴は、そもそも計算とは何かなんて考えた事もないんだろうな。
0540デフォルトの名無しさん2013/03/04(月) 22:48:42.18
そもそも計算とは何なの?
0541デフォルトの名無しさん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.82
いや、CとUNIXの汚さは副作用とか以前の問題だし……
0544デフォルトの名無しさん2013/03/04(月) 23:24:24.15
>>530
きっちりなんて曖昧でしたね、すいません。
「きっちり分けられる = 関数単位で分けられる」 です。
Haskell のプログラムの基本単位は関数です。

Haskell の言語仕様では関数単位で副作用の有無が定まります。
ステートメント単位とか、命令単位とか、行単位とかではなくて、
関数単位です。

戻り値が IO a 型ではない関数は、絶対に副作用はありません。
(本当は例外があるのですが、話がややこしくなるので今は考えません)
しかし、ほんの少しでも副作用をさせたいのなら、
その関数は IO a 型の値を戻さないといけません。
ほんの少しであっても、「その関数自体が副作用がある」と見なされます。

逆に IO a 型を戻す関数は、副作用があるかどうかは、
実はその関数の定義(中身)を見なければ明らかにはなりません。
ですが、この関数は中に副作用がある処理を含めることが「可能」なので、
IO a 型を戻す関数を内部に含む関数も IO b 型の値を戻すと決められています。

これらは言語仕様です。
プログラマが注意してそのように書くとこで安全性が保たれる、
というレベルの話ではなく、そうしなければコンパイルできないというレベルです。
>>537

コンパイラは関数の戻り値の型によって、
副作用が絶対に無い関数か、副作用がある可能性がある関数かを見分けます。

そして、ここが大事ですが、プログラマもコンパイルが通るように、
副作用がある関数か、副作用がない関数かをしっかり意識して分けます。
(初心者にとっては、分けざるを得ないという認識でしょうか)
0545デフォルトの名無しさん2013/03/04(月) 23:42:07.28
>>530
C言語でも分けられると言いますが、実際のところ、
Haskellのようにしっかり分けるCプログラマはまずいないでしょう。

実行効率やプログラムソースの読みやすさなど、理由はいくつかあります。

やろうと思えば分けられる言語と、分けることが前提の言語では全く違うと思います。

この辺りは、C vs C++ におけるオブジェクト指向と似てるかも知れません。
0546デフォルトの名無しさん2013/03/04(月) 23:52:28.17
C vs C++は酷かった
CでOOPできないと主張するために、OOPの必須条件が次々と追加されたよね
0547デフォルトの名無しさん2013/03/05(火) 00:26:28.70
haskellでは副作用がある部分とない部分を区別して書くことができます
じゃなくて
haskellでは副作用がある部分とない部分を区別しないと書けません
だろ

できることじゃなくてできないことに意味がある
カプセル化みたいなもん
0548デフォルトの名無しさん2013/03/05(火) 00:45:39.99
Haskellは全部副作用ありで書くことはできるんじゃない
■ このスレッドは過去ログ倉庫に格納されています