状態の変化に依存しない方が良いのはなぜですか?


16

この質問は、https://softwareengineering.stackexchange.com/questions/25569/is-haskell-worth-learningの質問から生じます。

一般に、Haskellが他の言語のコーディングスキルをどのように向上させるかについて、頻繁に繰り返されるステートメントがいくつか作成されます。さらに、これはHaskellがステートレスであるためであり、それは良いことです。

どうして?

誰かがこれを左手でタイプするだけ、あるいは一日目を閉じてタッチだけに頼るのと比較するのを見たことがあります。確かにそれ以上のものがありますか?

ハードウェアのメモリアクセス、またはパフォーマンスの大幅な向上に関連する何かに関連していますか?


2
Haskellはアカデミックです。Rich HickeyによるClojureについてのいくつかの講義を見るでしょう-そこで、彼は(Javierによる3つのポイントに似ていますが、簡単な方法で行われた)致命的な論争をします。
ジョブ


6
Haskellが「アカデミック」だからといって、それが非実用的または実用的ではないというわけではありません。
ティコンジャービス

回答:


17

私の頭の上には少なくとも3つの大きな利点があります。

  1. プログラムをより数式に近づけます。数学でxは、変わらず、方程式を解くまでそれが何であるかを知りません。

  2. 最後に、状態の変更があります(結局、これがコンピューターの低レベルでの動作です)。ただし、言語によって特定の場所に限定されます。コンパイラーは、他のコードが依存するものを変更しないことを知っているため、最適化のためにコードを移動する大きな機会をコンパイラーに与えます。

  3. 同時実行コードは不変データにアクセスするために同期する必要がないため、SMP共有メモリシステム(現在のすべてのマルチコアシステム)と疎結合クラスターの両方で同時実行性が向上します。


3
関数型プログラミングの提案は、ほとんどのストレス#3、すなわち、より簡単な同時実行プログラミングをもたらします。
-Mchl

4
@Mchl:私の経験では、彼らは「理解しやすく、推論するのが簡単」に最も重点を置いています。これは1に相当します。
sepp2k

+1、非常に完全な答え。@ sepp2k:どちらも重要だと思います。プログラムについての推論は私たちが毎日行うことであり、深く隠された関数で状態が変化していないことを確認する必要がない場合、高レベルのメソッドのみを読み取り、何が起こっているのかをキャッチする方がはるかに簡単です。ハードウェアに関して:マルチコアおよびマルチプロセッサにますます移行しているため(ホームコンピュータがマルチプロセッサを取得するまでにしばらく時間がかかると思います)、同時プログラミングを容易にする言語を持つことが重要です。
マチューM.

良い答え、#2は私が答えであると推定したものであり、マルチプロセッシングの利点についてよく読みましたが、明確で素晴らしい仕事とはほとんど言われていません。
オコド

1
@Yttrill、関数型言語はガベージコレクションに依存しているという点でユニークではなく、不変データを扱う場合、ガベージコレクションははるかに簡単です。命令ベースのアーキテクチャで計算を行うということは、状態を変更することを意味しますが、それは関数型言語の並列化がやや難しいという意味ではありません。関数型言語は並列性に揺さぶります。ルックアップデータと並行してHaskell、これは命令型言語に追加することはほとんど不可能な機能です。
dan_waterworth

4

もう1つの利点は、カップリングの削減です。次のようなコードがある場合:

 function doStuff(x) { return x + y;}

そしてあなたが持っている他の場所:

 function doOtherStuff(x) { y++; return y + x;}

その場合、2つの関数は暗黙的に依存します。呼び出しdoStuffが呼び出しによって影響を受けることを伝える簡単な方法はありませんdoOtherStuff。可変状態がなければ、接続を明示的にする必要があります。

もちろん、これはすべての可変状態に関する問題ではありません。問題は、広範にわたる可変状態に関するものです。本当の解決策は、デフォルトで不変性を持ち、必要な場所に変更可能な状態を「マーク」して制約する方法です。


+1。多くの経験豊富なプログラマーは上記のようなコードを書かないことを知っており、「この状態では可変状態は悪い」から「可変状態を大幅に減らしてより機能的に書き込もう」という大きなステップではありませんが、それは一歩です残念ながら少数のメーカー。
dan_waterworth

2

単純化した答えは、純粋に関数型の言語で名前を見ると、その定義を簡単に検索することで、関連付けられている値が何であるかがわかります。可変変数がある場合、その変数へのいくつかの割り当てのどれが最後に実行されたかを判断することしかできないため、制御フローも分析する必要があります。指数関数的な爆発を得るには、割り当てのRHS自体が変数に依存していることを考慮するだけでよいため、それらも再帰的に分析する必要があります。

上記の分析の一番下の行は、意図、不変条件、およびセマンティクスを説明するコメントなしでは受け入れられないことです:これらは解釈するのが難しく、実際のコードでセマンティクスが遵守されていることを検証するのが難しい場合があります。

この答えは、基本的に@Javierのポイント1の拡張です。

不正なOOレジームの人気の説明でもあると思います:OOでは、可変状態がカプセル化されているため、突然変異をある程度ローカライズし、セマンティクスのはるかに堅牢な表現と検証を可能にすることで、分析がはるかに簡単になります。

ただし、関数型プログラミングは答えではありません。正しい答えは、帰納的(機能的)プログラミングと共帰納的(手続き的)プログラミングの両方をサポートするシステムであるため、適切なツールはステートレスプログラミングとステートフルプログラミングの両方を処理できます。建設的(機能的)理論が十分に確立されているのに対して、国家管理の理論はまだ初期段階にあります。


関数型プログラミングと命令型プログラミングの混合は、Haskellが行うこととまったく同じです。通常の関数は機能的ですが、ステートフルな計算はdo表記法で表現できるため、(特に)可変状態を慎重に分離および制御できます。これが、最も実用的なSTM実装を持つ言語がHaskellである理由です。
ティコンジャービス

Do表記法には、それ自体でステートフルな計算を実行するものは何もありません。表記法は、モナド関数パイプラインの上にある単純な構文です。ステートフル計算は、モナドを使用して表現できるものの1つにすぎず、したがって表記法です。
ジョナサンスターリング

関数型プログラミングと命令型プログラミングの混在は、既存のほとんどすべての言語が行うことです。Haskellはステートフルな部分を分離する方法を提供したかもしれませんが、それは適切な組み合わせにはなりません:チャリティーはあるべき姿(IMHO)に似ています。
イットリル

2

Haskellで書かれたDBMS であるSiegeの作者として、可変状態に関する私の見解が矛盾していると言う人がいるかもしれません。そうでなければ見せたいと思います。

可変状態の目的は、システムの現在の状態を記述することです。あなたがブログを持ち、データベースによってバックエンドであるとすると、データベースは、クエリを行った時点でブログにある投稿を記述しますそれ。現在いくつの投稿がありますか?

これを、事実を伝えるために使用される不変の状態と比較してください。8月12日に何件の投稿がありましたか?

事実は推論するのは簡単ですが、可変状態はそうではありません。しかし、可変状態は、私たちの心の範囲から追放されるべきである悪の不純な効果ではありません。私たちが住んでいる不変の世界で共存するためにしばしばそれを必要とします、私たちはそれをもっと控えめに使用する必要があります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.