Haskell では副作用がモナドとしてモデル化されるのはなぜですか?
-
21-09-2019 - |
質問
Haskell における不純な計算がモナドとしてモデル化される理由について、誰かがヒントを提供してもらえますか?
つまり、モナドは 4 つの操作を備えた単なるインターフェイスですが、その中で副作用をモデル化する理由は何でしょうか?
解決
から検証を行うこととな機能です。いすべての影響で生として入力と出力パラメータ、そしてその機能は純粋なのです。
そのため、不純機能
f' :: Int -> Int
を追加しましたの概念の検討
f :: Int -> RealWorld -> (Int, RealWorld)
-- input some states of the whole world,
-- modify the whole world because of the side effects,
-- then return the new world.
その f
は純ます。定義されるのでしparametrizedデータタイプ IO a = RealWorld -> (a, RealWorld)
, のではないと思いますタイプが存在しくは
f :: Int -> IO Int
のプログラマの取り扱い実世界を直接も危険なプログラマーがその値の型が存在かもし コピー ることにより、基本的に不可能である。(いうコピーのファイルシステムです。これまでは?) そのため、当社の定義IOカプセル化の状態にします。
これらの不純機能を無駄にできないのであればチェーンされていったといわれている。検討
getLine :: IO String = RealWorld -> (String, RealWorld)
getContents :: String -> IO String = String -> RealWorld -> (String, RealWorld)
putStrLn :: String -> IO () = String -> RealWorld -> ((), RealWorld)
取り出したいファイル名からコンソールを読んでファイル印刷後のコンテンツです。どうすれば出来ない場合にアクセスできる実世界か
printFile :: RealWorld -> ((), RealWorld)
printFile world0 = let (filename, world1) = getLine world0
(contents, world2) = (getContents filename) world1
in (putStrLn contents) world2 -- results in ((), world3)
またパターンはこちらの関数が呼び出されるようになります:
...
(<result-of-f>, worldY) = f worldX
(<result-of-g>, worldZ) = g <result-of-f> worldY
...
いっそのことを指定するオペレーター ~~~
bind:イメージ
(~~~) :: (IO b) -> (b -> IO c) -> IO c
(~~~) :: (RealWorld -> (b, RealWorld))
-> (b -> RealWorld -> (c, RealWorld))
-> RealWorld -> (c, RealWorld)
(f ~~~ g) worldX = let (resF, worldY) = f worldX in
g resF worldY
そしてこの書
printFile = getLine ~~~ getContents ~~~ putStrLn
に触れることなく現実の世界です。
今また、ファイルの内容を大文字にします。Uppercasingは、純粋な機能
upperCase :: String -> String
もし現実の世界では、スを返します IO String
.やすいリフトなどの機能:
impureUpperCase :: String -> RealWorld -> (String, RealWorld)
impureUpperCase str world = (upperCase str, world)
この一般化:
impurify :: a -> IO a
impurify :: a -> RealWorld -> (a, RealWorld)
impurify a world = (a, world)
その impureUpperCase = impurify . upperCase
, にしき
printUpperCaseFile =
getLine ~~~ getContents ~~~ (impurify . upperCase) ~~~ putStrLn
(注:通常時においては getLine ~~~ getContents ~~~ (putStrLn . upperCase)
)
現在注目してみようになってい:
- 定義したオペレーター
(~~~) :: IO b -> (b -> IO c) -> IO c
るチェーンにつ不純機能と - 定義した関数
impurify :: a -> IO a
に変換する純粋な価値不純.
現在の同定 (>>=) = (~~~)
や return = impurify
, と。私たちはmonad.
(確認するmonadが数公理を満たすこと:
(1) return a >>= f = f a
impurify a = (\world -> (a, world))
(impurify a ~~~ f) worldX = let (resF, worldY) = (\world -> (a, world)) worldX
in f resF worldY
= let (resF, worldY) = (a, worldX))
in f resF worldY
= f a worldX
(2) f >>= return = f
(f ~~~ impurify) a worldX = let (resF, worldY) = impuify a worldX
in f resF worldY
= let (resF, worldY) = (a, worldX)
in f resF worldY
= f a worldX
(3) f >>= (\x -> g x >>= h) = (f >>= g) >>= h
ます。)
他のヒント
Haskell における純粋でない計算がモナドとしてモデル化される理由について、誰かがヒントを提供してもらえますか?
この質問には広く誤解が含まれています。不純物とモナドは独立した概念です。不純物は ない モナドによってモデル化されました。むしろ、次のようないくつかのデータ型があります。 IO
, 、命令型計算を表します。そして、それらの型の一部では、そのインターフェイスのごく一部が「Monad」と呼ばれるインターフェイス パターンに対応します。さらに、純粋/機能的/指示的な説明は知られていません。 IO
(そして、次のことを考慮すると、その可能性は低いです) 「シンビン」 の目的 IO
)、一般的に語られている話はありますが、 World -> (a, World)
の意味である IO a
。その話は真実を説明することはできません IO
, 、 なぜなら IO
同時実行性と非決定性をサポートします。この話は、計算中に世界との対話を可能にする決定論的計算の場合にはさえ機能しません。
詳しい説明については、を参照してください。 この答え.
編集:質問を読み直してみると、私の答えはまったく軌道に乗っているとは思えません。質問にあるように、命令型計算のモデルはモナドであることがよくあります。質問者は、モナド性によって命令型計算のモデル化が可能になるとは実際には想定していないかもしれません。
私の理解では、誰かが電話をかけてきました エウジェニオ・モッジ 彼は、「モナド」と呼ばれる、これまで曖昧だった数学的構造がコンピュータ言語の副作用をモデル化するために使用できることに最初に気づき、ラムダ計算を使用して副作用のセマンティクスを指定しました。Haskell が開発されていたとき、不純な計算をモデル化するさまざまな方法がありました (Simon Peyton Jones の記事を参照) 「ヘアシャツ」の紙 詳細については)、しかし Phil Wadler がモナドを導入すると、これが答えであることがすぐに明らかになりました。そして残りは歴史です。
えだが近のunpure計算にウをモデルとしていmonads?
ものではウ 純.必要な数学的概念と区別する unpure計算 や 純粋なもの 月 タイプレベルの モデル programm流 にした。
このときのツールを使用して、一定期間の一部のタイプ IO a
このモデルは、unpure計算である。そして知る必要があり方 組み合わせ これらの計算の 申請配列 (>>=
) リフト値 (return
は目の前にある、ことりと触れ合、基本となる。
これらの、すでにみんなを定義monad なものに対する考え方);)
また、monadsの提供 非常に一般的で迫力の抽象化, 多くの種類の制御フローを簡便でしかも一般化してmonadic機能 sequence
, liftM
または特別な構文、unpurenessなりました。
見 monadsにプログラミング や 独自性を打 (はけん)。
は、Monad
は非常にシンプルな構造です。答えの半分は次のとおりです。Monad
は、我々は、おそらく副作用関数に与え、それらを使用することができることができることを、最も簡単な構造です。 (Monad
)私たちは、副作用の値(return
)として、純粋な値を扱うことができ、私たちは新たな副作用の値を取得するには副作用の値に副作用関数を適用することができます>>=
で、私たちは2つのことを行うことができます。これらのもののいずれかを実行する能力を失う私達の副作用のタイプは「少なくとも」Monad
する必要があり、それがMonad
が判明ので、壊滅的だろうと、私たちはこれまでに必要なてきたすべてのものを実装するのに十分です。
残りの半分は次のとおりです。私たちは、「副作用の可能性」に与えることができる最も詳細な構造は何ですか?我々は確かに集合(会員である必要が唯一の操作)など、すべての可能な副作用のスペースを考えることができます。我々は彼らを次々に実行して2つの副作用を組み合わせることができ、これは異なる副作用を生じ(あるいは同じものを与えるだろう - まず、その結果だった「シャットダウンコンピュータ」と第二は、「ライト・ファイル」だった場合これらを構成するだけの「シャットダウンコンピュータ」)です。
[OK]を、私たちは、この操作について何を言うことができますか?それは連想です。我々は3つの副作用を組み合わせた場合、それは我々がで組み合わせる。私たちは、その後シャットダウン・コンピュータ(ライト・ファイルは、ソケットを読んで)行う場合、それは、書き込みファイルを実行するのと同じです(読みソケットその後、シャットダウンを行ういるため問題ではないされていますコンピューター)。しかし、それは可換ではありません。(「ライト・ファイル」、次に「削除ファイルは」)(「ファイル削除」し、「ライト・ファイル」)とは異なる副作用です。そして、我々はアイデンティティ持っている:「!グループを」特別な副作用「副作用のない」作品(「副作用なし」し、「削除ファイルは」ちょうど「削除ファイル」と同じ副作用である)任意の数学者が考えているこの時点ではしかし、グループは逆行列を持ち、一般的に副作用を反転させる方法はありません。 「削除ファイルは、」不可逆的です。だから私たちは残っている構造は、当社の副作用関数はモナドなければならないことを意味しモノイドのことです。
より複雑な構造がありますか?承知しました!私たちは、ファイルシステムベースのエフェクト、ネットワークベースのエフェクト、よりに起こりうる副作用を分割でき、我々はこれらの詳細を保存し、組成物のより精巧なルールを思い付くことができます。 Monad
は非常にシンプルで、まだ我々が気にプロパティのほとんどを表現するための強力な十分な:しかし、再び、それはに降りてきます。 (具体的には、結合性および他の公理は、私たちは複合アプリケーションの副作用は、作品の副作用の組み合わせと同じになることを自信を持って、小さな断片に私たちのアプリケーションをテストしてみましょう)。
これは実際には機能的な方法でI / Oを考えると非常にきれいな方法です。
は、ほとんどのプログラミング言語では、入力/出力操作を行います。 Haskellでは、がの操作が、操作のリストを生成するためには、あなたがやりたいんにないコードを書くことを想像します。
モナドまさにそのためだけのかなりの構文です。
あなたが何か他のものではなく、モナドとしての理由を知りたい場合は、、私は答えは、彼らが人々がHaskellのを作っていた時に考えることができるとI / Oを表現するのに最適な機能的な方法だということだと思います。
私の知る限りでは、その理由は、型システムにおける副作用チェックを含むことができることです。あなたがもっと知りたい場合は、それらの SE-ラジオのエピソードに耳を傾けます: エピソード108:サイモンペイトンジョーンズ関数型プログラミングとHaskellの上 エピソード72:LINQのエリックマイヤー
上記は理論的背景を持つ非常に良い詳細な回答があります。しかし、私はIOモナドの私の見解を与えたいです。私はそれが非常にナイーブあるいは間違っているそうであってもよいし、Haskellのプログラマを経験したわけではありません。しかし、私は(それが他のモナドに関連していないことに注意してください)ある程度モナドIOに対処するために私を助けてくれます。
まず、私たちはその(現実世界)以前の状態にアクセスすることができないとして、「現実世界」でその例があまりにも私のためにクリアされていないと言いたいです。それは全く計算をモナドに関するないが、それは一般的にHaskellコードで提示され、参照透明性の意味で望ましいとすることができる。
だから我々は我々の言語(Haskellは)純粋になりたいです。しかし、我々は我々のプログラムは有用ではないことができ、それらのないように、入力/出力操作を必要としています。そして、これらの操作は、その性質上、純粋にすることはできません。唯一の方法はこれに対処するように、我々は、コードの残りの部分とは別の不純な操作にしています。
ここでモナドています。実は、私は同様の必要な特性を有する他の構築物が存在しないことを、確認していないが、それは使用することができますので、ポイントは、それはこれらの性質を持っているモナドである(そしてそれが正常に使用されます)。主な特性は、我々はそれから逃れることができないということです。モナドインターフェイスは、私たちの価値の周りにモナドを取り除くための操作を持っていません。他の(ないIO)モナドは、このような操作を提供し、パターンマッチング(例えば、多分)を可能にするが、これらの操作はモナドインタフェースではありません。もう一つの必要なプロパティは、チェーンオペレーションの能力です。
我々は型システムの観点から必要なものを考える場合は、、我々は任意の谷に巻き付けることができ、コンストラクタ、と入力する必要があるという事実に来ます。我々はそれ(すなわち。パターンマッチング)から脱出禁止としてコンストラクタは、プライベートでなければなりません。しかし、我々は、(ここでリターンが頭に浮かぶ)このコンストラクタに値を配置する機能を必要としています。そして、我々は、チェーンオペレーションの方法が必要です。私たちはいくつかの時間のために考えてみれば、私たちは実際に来る、その連鎖操作は>> =とタイプを持っている必要があります。だから、私たちはモナドと非常によく似たものに来ます。私たちは今、この構造で可能な矛盾した状況を分析した場合、我々はモナド公理に来る、と考えています。
先進構築物は、不純物と共通のものを持っていないことに注意してください。それだけで私たちは不純な操作に対処できるようにする必要がありますことを望んだの特性、すなわち、無エスケープチェーン接続、およびに取得する方法を持っています。
次に不純な動作のいくつかのセットがこの選択されたモナドIO内言語で事前に定義されています。私たちは、新たな不純オペレーションを作成するために、これらの操作を組み合わせることができます。そして、これらすべての操作は、その種類にIOを持っている必要があります。しかし注意し、いくつかの機能のタイプでIOの存在は、この機能の不純をすることはありません。私が理解としてではなく、純粋と不純な機能を分離するために最初に私たちのアイデアだったとして、その種類にIOと純粋な関数を記述することは悪い考えである。
最後に、私はモナドは純粋なものに不純な操作を有効にしないこと、言いたいです。それだけで、それらを効果的に分離することができます。 (私はそれが唯一の私の理解であることを、繰り返し)