@@ -5,7 +5,7 @@ headingBackgroundImage: ../../img/background.png
5
5
headingDivClass : post-heading
6
6
author : Mizunashi Mana
7
7
postedBy : Mizunashi Mana
8
- date : April 04 , 2020
8
+ date : April 05 , 2020
9
9
tags :
10
10
...
11
11
---
@@ -16,15 +16,15 @@ Haskell は他のプログラミング言語には見られない特徴を多く
16
16
17
17
## 純粋性とは何か
18
18
19
- Haskell は純粋関数型プログラミング言語 (purely functional programming language) を売りにしている。関数型 (functional) の部分は他に任せるとして、ここでは純粋性 (purely) に着目しよう。純粋性とはなんだろうか ? どういう条件を満たせば、プログラミング言語は純粋と言えるんだろうか? [ Haskell の公式サイト] ( https://www.haskell.org/ ) ではこう述べられている:
19
+ Haskell は純粋関数型プログラミング言語 (purely functional programming language) を売りにしている。関数型 (functional) の部分は他に任せるとして、ここでは ** 純粋 (purely)** の部分に着目しよう。純粋とはなんだろうか ? どういう条件を満たせば、プログラミング言語は純粋と言えるんだろうか? [ Haskell の公式サイト] ( https://www.haskell.org/ ) ではこう述べられている:
20
20
21
21
> Every function in Haskell is a function in the mathematical sense (i.e., "pure").
22
22
>
23
23
> Haskell の全ての関数は、数学の意味での関数 (つまり「純粋」) です。
24
24
>
25
25
> -- https://www.haskell.org/
26
26
27
- ふむ、数学的な意味での関数とはなんだろうか? 関数が純粋とはどういうことを指すんだろうか? これは噛み砕くと、
27
+ ふむ、どうやら全ての関数が、数学的な意味での関数であれば、そのプログラミング言語は純粋と言えるようだ。ところで、 数学的な意味での関数とはなんだろうか? 関数が純粋とはどういうことを指すんだろうか? これは噛み砕くと、
28
28
29
29
1 . 関数はどんな時も、同じ引数を与えられたら同じ結果を返す
30
30
@@ -95,7 +95,7 @@ putStrLn :: String -> IO ()
95
95
* 動作、 つまり「 何をするか」 を表す値を持つ
96
96
* その動作をした結果、 得られる値の型が `a` であることを表す
97
97
98
- [^ in - other- words ]: 動作は、 計算 (computation) とも呼ばれる。
98
+ [^ in - other- words ]: 動作は、 計算 (computation) とも呼ばれる。 また 、 日本の Haskell コミュニティでは 、 英語そのままで 「 アクション 」 とも呼ばれている 。
99
99
100
100
型だ。 抽象的すぎてあまりピンとこないかもしれない。 もし、 その動作が結果を返す以外に何もしないなら、 それは純粋な操作であるから、 次のように書ける:
101
101
@@ -193,7 +193,7 @@ Haskell の `putStrLn` が純粋な理由は分かってもらえただろうか
193
193
194
194
> 主張は分かったが、純粋に扱うだけに制限するということは、普通のプログラミング言語より非純粋な動作を上手く扱えないんじゃないか
195
195
196
- と疑問に思う人もいるだろう。これも当然の疑問だ。普通のプログラミング言語は、表現力豊で 、様々な制御構文を持ち、それぞれの構文が純粋性に拘らないため、とてもユニークな非純粋なプログラムを書くことができる。ただ、安心して欲しい。Haskell も、それに負けない表現力で、非純粋な動作を作成することができる。さて、Haskell は、普通のプログラミング言語の機構の基盤は
196
+ と疑問に思う人もいるだろう。これも当然の疑問だ。普通のプログラミング言語は、表現力豊かで 、様々な制御構文を持ち、それぞれの構文が純粋性に拘らないため、とてもユニークな非純粋なプログラムを書くことができる。ただ、安心して欲しい。Haskell も、それに負けない表現力で、非純粋な動作を作成することができる。さて、Haskell は、普通のプログラミング言語の機構の基盤は
197
197
198
198
* 2つの動作を上手く結合できること
199
199
@@ -362,7 +362,7 @@ ifIO b act1 act2 = case b of
362
362
363
363
このプログラムは、条件を表す引数と、`IO` 動作を2個受け取り、条件によって2つの動作のうちのどちらかを返していた。これは考えてみれば、とても不思議で強力なことだと思わないだろうか? 普通のプログラミング言語の `if` 文は、条件から書かれたプログラムのどちらかを実行する。一方、`ifIO` は実行を制御しているわけではない。単に、普通の関数と同じように、2つの動作を受け取って、そのうちの片方を関数の返り値として返すだけだ。`ifIO` を呼び出したプログラマは、返ってきた動作をゴミ箱に捨ててもいいし、`(>>=)` で繋げて「2回続けて同じ動作をする」1つの動作にしてもいい。もちろんその動作も `main` に組み入れるかはプログラマ次第だ。なんなら、`main` 以外にライブラリの一部としてグローバルに定義してもいい。ライブラリを使うユーザは、やっぱりそれを使うも使わないも自由だ。`main` に組み入れない限り、その動作は単なるデータであり、実行もされない。
364
364
365
- ` IO ` 動作がデータであることは、プログラムをより豊にする 。さっきの ` ifIO ` は、条件によって片方の動作を返していた。` IO ` 動作はもっと多彩に制御できる。例えば、条件によって動作の順番を変えたかったら次のように書けばいい:
365
+ ` IO ` 動作がデータであることは、プログラムをより豊かにする 。さっきの ` ifIO ` は、条件によって片方の動作を返していた。` IO ` 動作はもっと多彩に制御できる。例えば、条件によって動作の順番を変えたかったら次のように書けばいい:
366
366
367
367
``` haskell
368
368
chooseOrderIO :: Bool -> IO a -> IO a -> IO a
@@ -439,7 +439,9 @@ newtype IO a = IO (State# RealWorld -> (# State# RealWorld, a #))
439
439
IO $ \ s# -> (# s# , \ () -> s# # )
440
440
```
441
441
442
- は ` s# ` を2箇所で使ってるため ` IO (() -> State# RealWorld) ` の値になれないし、
442
+ は [ ^ special-syntax-for-unboxed-tuples ] ` s# ` を2箇所で使ってるため ` IO (() -> State# RealWorld) ` の値になれないし、
443
+
444
+ [ ^ special-syntax-for-unboxed-tuples ] : ` (# x, y #) ` は ` (# a, b #) ` 型の値を表す特別な構文だ。ここでは詳細は述べないので、` x ` と ` y ` のタプルの特別な表記方法だと思ってもらって構わない。
443
445
444
446
``` haskell
445
447
IO $ \ s# -> (# s# , IO $ \ _ -> (# s# , () # ) # )
@@ -597,6 +599,6 @@ main = IO $ \r0# ->
597
599
598
600
* ` State# RealWorld ` の型の値は、必ず1回だけ使用される
599
601
600
- という契約も意義が見えてくる。もし、この契約が破られると、途中でデータ依存が分岐したり、または宙に消えたりすることになる 。そうなると、動作がどういう挙動をするかは、Haskell 内では規定されなくなってしまう。実際に、最適化によってどう動作するかが変わってきてしまう例も作れる。` IO ` の契約とは、データ依存が必ず一本の線で繋がり、Haskell の評価の枠できちんと順番が規定されるということを保証しているのだ。
602
+ という契約も意義が見えてくる。もし、この契約が破られると、途中でデータ依存が分岐したり、または途中で途絶えたりすることになる 。そうなると、動作がどういう挙動をするかは、Haskell 内では規定されなくなってしまう。実際に、最適化によってどう動作するかが変わってきてしまう例も作れる。` IO ` の契約とは、データ依存が必ず一本の線で繋がり、Haskell の評価の枠できちんと順番が規定されるということを保証しているのだ。
601
603
602
604
これが、GHC がこのような定義を ` IO ` で採用している理由になる。もちろん、アナロジーとして現実世界全体を表す架空の状態を ` State# RealWorld ` と見立て、` IO ` 動作の実行により新たな現実世界全体の状態が手に入るという見方は可能だ。名前の由来もそこから来ている。ただ、基本的には、GHC において、特別な仕組みを入れずに ` IO ` を実装するためのやり方であるということを押さえておいて欲しい。
0 commit comments