質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Haskell

Haskellは高い機能性をもった関数型プログラミング言語で、他の手続き型プログラミング言語では難しいとされている関数でも容易に行うことができます。強い静的型付け、遅延評価などに対応しています。

Q&A

解決済

1回答

291閲覧

純粋関数型言語のモナドについて

ASID

総合スコア7

Haskell

Haskellは高い機能性をもった関数型プログラミング言語で、他の手続き型プログラミング言語では難しいとされている関数でも容易に行うことができます。強い静的型付け、遅延評価などに対応しています。

2グッド

1クリップ

投稿2018/09/26 09:34

モナドについて

3つ質問があります。

  1. モナドは、引数を取らない関数のような物で包み込まれて
    評価 → その包がとれる = 入出力など行わないので参照透過
    評価して実行? → 包がとれる → 入出力などの副作用ある関数が評価される。
    みたいな認識で合ってますか?
  2. FunctorとApplicativeとMonadの違い
  3. 何故モナドを使うのか?

高校生なので、圏論がわかりません。なので、出来れば他の言語で擬似的に実装してくれるとありがたいです。

johnny, manzyun👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

まず、モナドを抽象的なまま理解しようとするのは難しいと思います。具体的なモナドをいくつか理解した上でそれら共通点を見出す方が簡単かと思います。

また、Haskell を使う上で圏論を理解する必要はありません。

モナドは、引数を取らない関数のような物で包み込まれて

評価 → その包がとれる = 入出力など行わないので参照透過
評価して実行? → 包がとれる → 入出力などの副作用ある関数が評価される。
みたいな認識で合ってますか?

質問の表現が理解しきれていませんが、入出力という単語があるのでおそらく IO モナドを念頭に置いているのだろうという想像で回答します。

例えば putStrLn "hi"IO () 型の値で「手続き」を表します、これを評価しても「手続き」以上の意味はなく、標準出力に「hi」が出力されるわけではありません。ここで seqseq a ba を先に評価する特殊な関数です。(Wandbox で実行

haskell

1main :: IO () 2main = seq (putStrLn "hi") $ pure ()

JavaScrpit でムリヤリ実装すると次のような感じでしょうか。

javascript

1class Unit {} 2unit = new Unit(); 3 4hi = function () { console.log("hi"); return unit; } 5 6hi

「手続き」を実行するためには main に埋め込む必要があります。(unsafePerformIO というものもありますが、ここでは説明しません。)(Wandbox で実行

haskell

1main :: IO () 2main = putStrLn "hi"

javascript

1class Unit {} 2unit = new Unit(); 3 4hi = function () { console.log("hi"); return unit; } 5 6main = hi // main は処理系によって特別扱いされる変数と仮定します

「手続き」は単なる値で、main が特殊扱いされて実行されることに注意してください。

FunctorとApplicativeとMonadの違い

これらを重点的に説明したのが『すごい Haskell たのしく学ぼう!』です。この書籍を読むことをおすすめします。ここではリストモナドに限って説明します。その書籍の半分ほどの分量をそれら説明が占めているので、全部説明しようとするとその量になってしまいますから。

ファンクターであれば次のことができるようになります。(> は REPL のプロンプトと見てください。)

haskell

1> (* 2) <$> [1, 2, 3] 2[2, 4, 6]

javascript

1function map (f, l) { return l.map(f); } 2 3map(x => x * 2, [1, 2, 3]);

アプリカティブファンクターであれば、上記に追加して次のことができるようになります。

haskell

1> [(* 2), (+ 1)] <*> [1, 2, 3] 2[2, 4, 6, 2, 3, 4]

javascript

1function flat (l) { return l.reduce((a, v) => a.concat(v), []); } 2function apply (fs, l) { return flat(fs.map(f => l.map(f))); } 3 4apply([x => x * 2, x => x + 1], [1, 2, 3]);

モナドであれば、上記に追加して次のことができるようになります。

haskell

1> [1, 2, 3] >>= \x -> ['a' : show x, show x <> "b"] >>= \y -> pure (x, y) 2[(1, "a1"), (1, "1b"), (2, "a2"), (2, "2b"), (3, "a3"), (3, "3b")]

javascript

1function flat (l) { return l.reduce((a, v) => a.concat(v), []); } 2function bind (a, b) { return flat(a.map(e => b(e))); } 3function pure (a) { return [a]; } 4 5bind([1, 2, 3], x => bind(['a' + x, x + 'b'], y => pure([x, y])));

これには do 記法が用意されているため、次のように書くこともできます。どちらでも同じ意味です。

haskell

1> do { x <- [1, 2, 3]; y <- ['a' : show x, show x <> "b"]; pure (x, y) }

何故モナドを使うのか?

モナドを明示的に扱っていない言語でも、実はいろいろなモナドが使われています。

例えば次のようなものがあります。

  • リスト内包表記
  • async/await
  • ?. 演算子
  • 例外

多くの言語ではこれらに別々の記法を与えて扱っていますが、モナドに対する記法を1つサポートするだけでこれらは全て扱えます。

そういった意味で言語が簡単になります。

投稿2018/09/27 04:35

編集2018/09/27 06:14
kakkun61

総合スコア285

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ASID

2018/09/27 14:05

すごいH本買ってみようかと思います。 こんな質問に回答がくると思わなかったです。しかも長文で書いてくださり、本当にありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問