@@ -22,7 +22,7 @@ Haskell は純粋関数型プログラミング言語 (purely functional program
22
22
>
23
23
> Haskell の全ての関数は、数学の意味での関数 (つまり「純粋」) です。
24
24
>
25
- > -- https://www.haskell.org/
25
+ > -- [ haskell.org ] ( https://www.haskell.org/ ) Features: Purely functional より
26
26
27
27
ふむ、どうやら全ての関数が、数学的な意味での関数であれば、そのプログラミング言語は純粋と言えるようだ。ところで、数学的な意味での関数とはなんだろうか? 関数が純粋とはどういうことを指すんだろうか? これは噛み砕くと、
28
28
@@ -100,9 +100,7 @@ putStrLn :: String -> IO ()
100
100
型だ。 抽象的すぎてあまりピンとこないかもしれない。 もし、 その動作が結果を返す以外に何もしないなら、 それは純粋な操作であるから、 次のように書ける:
101
101
102
102
```haskell
103
- data PureAction a = PureAction
104
- { runPureAction :: () -> a
105
- }
103
+ data PureAction a = PureAction (() -> a )
106
104
```
107
105
108
106
つまり、 引数が何もない純粋関数だ。 例えば、 整数を2 つ受け取って、 その和を計算する動作を返す関数は次のように書けるだろう:
@@ -137,9 +135,9 @@ addAction x y = PureAction (\_ -> x + y)
137
135
2 . 結果を捨て
138
136
3 . ` () ` を返す
139
137
140
- というプログラムだ。このプログラムを評価しても、結果の ` () ` だけしか目にしないはずで、何回実行しても同じ結果が得られるはずだ。そう説明すると、ちょっと Haskell をかじった人は
138
+ というプログラムだ。このプログラムを評価しても、` () ` だけしか目にしないはずで、何回実行しても同じ結果が得られるはずだ。つまり、 ` putStrLn ` は余計なことを何もしていないと言えるだろう 。そう説明すると、ちょっと Haskell をかじった人は
141
139
142
- > この説明は間違っている。この式は ` putStrLn "str" ` を全く評価していないので、実際に ` putStrLn "str" ` が余計なことを何もしていないかは分からない。
140
+ > この説明は間違っている。この式は ` putStrLn "str" ` を全く評価していないので、実際に ` putStrLn "str" ` が余計なことを何もしていないかは分からない
143
141
144
142
と言うだろう。その通りだ。この説明は間違っている。それを確認してみよう:
145
143
@@ -148,7 +146,7 @@ addAction x y = PureAction (\_ -> x + y)
148
146
()
149
147
```
150
148
151
- もし、さっきの ` putStrLn "str" ` がちゃんと計算されていたなら、今回は ` something happened! ` というエラーが見れるはずだ。ところが、全く何の問題もなく式の実行は終わり、` () ` が出力されてしまった。では、ちゃんと修正してみよう。修正は、` seq ` という魔法の関数を使うことで可能だ:
149
+ もし、さっきの ` putStrLn "str" ` がちゃんと計算されていたなら、今回は ` something happened! ` というエラーが見れるはずだ。ところが、全く何の問題もなく式の実行は終わり、` () ` が出力されてしまった。Haskell は遅延評価により、最終結果に本当に必要な部分しか計算してくれないので、 ` putStrLn "str" ` の部分は計算されず無視されてしまっていただけのようだ。 では、ちゃんと修正してみよう。修正は、` seq ` という魔法の関数を使うことで可能だ。 ` seq :: a -> b -> b ` は一番最初に渡された引数を (必要かどうかに関わらず、強制的に) 計算し、その後2番目の引数を返す関数だ。この関数を使うと、次のように修正が可能だ :
152
150
153
151
``` haskell
154
152
>>> putStrLn " str" `seq` ()
@@ -157,7 +155,7 @@ addAction x y = PureAction (\_ -> x + y)
157
155
*** Exception : something happened!
158
156
```
159
157
160
- 今度は大丈夫だろう。` putStrLn "str" ` の部分をエラーに変えると、ちゃんとエラーが出力されている。そう、` putStrLn "str" ` が実行されて実際に行われるのは、その定義通り
158
+ 今度は大丈夫だろう。` putStrLn "str" ` の部分をエラーに変えると、ちゃんとエラーが出力されている。` putStrLn "str" ` は計算されているようだ。 そう、` putStrLn "str" ` が実行されて実際に行われるのは、その定義通り
161
159
162
160
* 「ターミナルに ` "str" ` を出力する動作」を返す
163
161
@@ -410,7 +408,7 @@ Haskell の IO モナドとは、動作そのものを値に持つ型だった
410
408
411
409
ところで、もしかしたら、読者の中には、
412
410
413
- > Haskell の IO モナドは、現実世界を状態にする State モナドだ。
411
+ > Haskell の IO モナドは、現実世界を状態にする State モナドだ
414
412
415
413
という主張を、見たことがある人がいるかもしれない。最後におまけとしてこの話に触れておこうと思う。気になる人は、この後も呼んでみると、` IO ` モナドの理解の助けになるかもしれない (または、むしろ混乱するかもしれない。もし、混乱したなら、とりあえずこの話は忘れることをお勧めする。ここに書いてある話を理解しなくても、` IO ` モナドの利用に関して全く支障はない。そういう話もあるぐらいの事柄だ。なので、安心してまずは Haskell プログラミングを楽しんでほしい。いつか楽しみ飽きたら戻ってきてもいいかもしれない)。
416
414
@@ -493,14 +491,14 @@ IO $ \r0# ->
493
491
False
494
492
```
495
493
496
- ` b1 ` と ` b2 ` は両方とも ` readMutVar# var# r1# ` から得た値になる。ところが、これらを比較してみると ` False ` になる [ ^ notice-undefined-behavior ] 。なお、この式は、` IO ` 型で定義しているが、実際には
494
+ ` b1 ` と ` b2 ` は両方とも ` readMutVar# var# r1# ` から得た値になる。ところが、これらを比較してみると ` False ` になる [ ^ notice-undefined-behavior ] 。もし、 ` readMutVar# ` が純粋なら、 ` b1 ` と ` b2 ` の結果は同じになるため、上の評価結果は ` True ` になるはずだ。しかし、残念ながら ` readMutVar# ` は純粋ではないので、 ` b1 ` と ` b2 ` は異なる値になってしまう。 なお、この式は、` IO ` 型で定義しているが、実際には
497
495
498
496
* 2 回目の ` readMutVar# ` の呼び出しで ` r1# ` を 2 回使用しているし、
499
497
* 返ってきた ` State# RealWorld ` の値を捨てている
500
498
501
499
[ ^ notice-undefined-behavior ] : 実際には、最適化次第で結果が変わることもある。
502
500
503
- ので契約違反であることに注意だ。
501
+ ので契約違反であることに注意だ。GHCi 上で、うまく評価結果を確認するために、 ` IO ` を使っている。
504
502
505
503
さて、純粋性を守れないなら、GHC は一体全体何のためにこのような定義をしているんだろう? 関数が純粋でなくてもいいなら、単に
506
504
@@ -557,7 +555,7 @@ IO f >>= g = IO $ \r0# ->
557
555
特に、` (>>=) ` の定義が重要になる。` (>>=) ` が返してくる ` IO ` の中身は、
558
556
559
557
1 . 受け取った ` State# RealWorld ` をまず最初の ` IO ` 動作に渡す
560
- 2 . その結果出てきた結果を ` g ` に渡して、次の ` IO ` 動作を生成する
558
+ 2 . その結果を ` g ` に渡して、次の ` IO ` 動作を生成する
561
559
3 . 生成した ` IO ` 動作に、最初の ` IO ` 動作が返してきた ` State# RealWorld ` を渡す
562
560
563
561
ということを行っている。これにより、
0 commit comments