お客さんが最近関数型プログラミングに興味を持っているため、
私もいろいろ調べているのですが、疑問しか出なかったので質問させてください。
疑問は主には以下3点です。
-
副作用とはなにか
-
関数型の言語(Haskellとか)を使う利点とは
-
関数型で情報の蓄積は可能なのか
-
副作用とはなにか
関数型のメリットに、副作用がなくなるというのが、いろいろなサイトで言われています。
しかし、その副作用の説明がバラバラで、結局何が言いたいのかがまったくわかりません。
日本語としては、
副作用 = 副次的な作用
なので、普通に考えれば以下①~⑥のようになる認識です。
C#
1using System; 2 3namespace CSharpTes 4{ 5 class Program 6 { 7 static void Main(string[] args) 8 { 9 int begin = 1; 10 int end = 100; 11 12 A classA = new A(); 13 for (int i = begin; i <= end; i++){ 14 classA.add(i); 15 } 16 17 B classB = new B(); 18 for(int i = begin; i <= end; i++){ 19 classB.add(i); 20 } 21 22 C classC = new C(); 23 24 Console.Out.WriteLine(classA.sum()); 25 Console.Out.WriteLine(classB.getSum()); 26 Console.Out.WriteLine(classC.add(begin, end)); 27 Console.ReadKey(); 28 } 29 } 30 31 // リストもどき 32 class A{ 33 _A data; 34 public A() 35 { 36 // 条件分岐を減らすために入れている 37 // これは今回の論点ではありません。 38 data = new _A(0); 39 } 40 public void add(int num){ 41 _A newData = new _A(num); // ① データの追加なので作用 42 getEndData().next = newData; // ② それまでの最後尾のリストのデータが変わるため副作用 43 } 44 private _A getEndData() { 45 _A current = data; 46 while (current.next != null){ 47 current = current.next; // ③ 再代入だが副作用とは言えない 48 } 49 return current; 50 } 51 public int sum(){ 52 _A current = data; 53 int sum = 0; 54 while (current.next != null){ 55 current = current.next; // ④ ③と同じ処理だがこっちは副次的なものなので副作用と言える 56 sum += current.num; // ⑤ 合計するのが関数の主旨なので作用 57 } 58 return sum; 59 } 60 }; 61 62 class _A{ 63 public int num; 64 public _A next; 65 public _A(int num){ 66 this.num = num; 67 } 68 69 }; 70 class B{ 71 int sum; 72 public void add(int num){ 73 sum += num; // ⑥ 合計するのが関数の主旨なので作用 74 } 75 public int getSum() 76 { 77 return sum; 78 } 79 }; 80 81 // 関数型? 82 class C{ 83 // 状態の変化は起こらない? 84 public int add(int begin, int end){ 85 if(begin >= end){ 86 return begin; 87 } 88 return begin + (add(begin + 1, end)); 89 } 90 }; 91}
また、「IO処理は副作用」という記述を見ましたが、
「IO処理の際にファイルポインタの移動等が発生するから副作用が多い」
という意味であっているでしょうか。
①~⑥、およびIO処理の認識が
あっているのか間違っているのか、理由を添えて教えていただきたく。
- 関数型の言語(Haskellとか)を使う利点とは
これまで色々な技術を見て、そのたびに「こういうことに使えそう」、
「あの案件の時に使えていればよかった」等思いました。
(手続き型からオブジェクト指向への移行時や、MVC、MVVMを知った時等々)
しかし、今回関数型のことを調べても、利点がまったく思いつきません。
色々なサイトに、状態の変化がなくなるためにバグが減る、
とありますが、チラっと実装した結果、私にはそのようには思えませんでした。
C等の言語を関数型に置換する際、再帰処理が散見されますが、
そもそもC等の言語は、「再帰処理は複雑なため、バグが多くなりやすく、メンテナンス性も悪くなるので控える」
みたいな流れがあったと思います。
(まぁ、昔はメモリも少なかったというのもありますが、それは瑣末な問題です。)
アルゴリズムが完璧にかければ減るのでしょうが、
関数型の書き方が人間には複雑に見え、実装時のポカミスが増える気がします。
- 関数型で情報の蓄積は可能なのか
ここだけ実装の話になってしまいますが、
再代入が許可されていないHaskell等の関数型で情報の蓄積は可能なのでしょうか。
(DBやファイルに書き込むという話はナシで)
以上
回答を頂いても反論してしまうと思いますが、お付き合いいただければと思います。
回答を受け追記
今のところの私の理解を追記します。
- 副作用とは
関数外に影響を及ぼす操作
→関数外までスコープが及ぶ変数の読み書き、ファイルの読み書き
- メリット
ある程度複雑な対話が必要なシステムには不向きだが、
数学の関数ように入力→出力のみのプログラムに向いている
- 情報の蓄積
その時々によって情報を書き換える必要があるため関数型には不向き
しかし実装は可能
回答3件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2016/10/04 12:37
2016/10/04 17:56
2016/10/06 01:39
2016/10/06 04:13 編集