
そして、関数を適用する方法を知っています。

小学校。 それでは、タスクを複雑にしてみましょう-コンテキストが重要です。 今のところ、コンテキストは単に値を入力できるボックスと考えることができます。

これで、この値に関数を適用すると、コンテキストに応じて異なる結果が得られます 。 これは、ファンクター、適用ファンクター、モナド、矢印などが基づいている主要なアイデアです。
Maybe
データ型は2つの関連するコンテキストを定義します:

data Maybe a = Nothing | Just a
後で、
Just a
vs
Nothing
関数の動作の違いを確認します。 しかし、最初にファンクターについて話しましょう!
ファンクター
コンテキストに値がパックされている場合、通常の関数を取得して適用することはできません。

そして、ここで
fmap
助けを急いでいます。
fmap
通りの男、
fmap
はコンテキストについて多くのことを知っています。 彼はすでに、コンテキストにパックされた値に関数を適用する方法を知っています。
Just 2
(+3)
を適用するとします。
fmap
使用します。
> fmap (+3) (Just 2) Just 5

バム!
fmap
はその方法を示しました! しかし、彼はどのように関数を正しく適用するかをどのように知っていますか?
それでは、実際にファンクターとは何ですか?
ファンクターは型クラスです。 彼の定義は次のとおりです。

ファンクターは、
fmap
がどのように適用されるかが決定されるデータ型です。 そして、これが
fmap
仕組みです:

だから私たちにできることは:
> fmap (+3) (Just 2) Just 5
また、
fmap
ファンクタである可能性があるため、この関数
fmap
魔法のように適用します。
Just
and
Nothing
関数を適用する方法を定義します:
instance Functor Maybe where fmap func (Just val) = Just (func val) fmap func Nothing = Nothing
これは、
fmap (+3) (Just 2)
を記述するときにバックグラウンドで発生することです。

そして、あなたは言う:「さて、
fmap
、しかし
Nothing
適用し
Nothing
ください
(+3)
。」

> fmap (+3) Nothing Nothing

ビル・オライリーは、おそらくファンクターには意味がない
The MatrixのMorpheusと同様に、
fmap
何をすべきかを知っています。 あなたは
Nothing
で始まり、
Nothing
でも終わりました! これは
fmap
zenです。 そして今、一般に
Maybe
データ型が存在する理由が明らかになりました。 ここで、たとえば、
Maybe
せずに言語でデータベースへの書き込みをどのように処理します
Maybe
:
post = Post.find_by_id(1) if post return post.title else return nil end
Haskellの場合:
fmap (getPostTitle) (findPost 1)
findPost
がメッセージを返す場合、
findPost
を使用してヘッダーを
getPostTitle
ます。 彼が
Nothing
を返すなら、私たちは
Nothing
を返します! くそー、エレガント?
<$>
は
fmap
挿入形です。そのため、上記のコードの代わりに次のコードを見つけることができます。
getPostTitle <$> (findPost 1)
別の例を次に示します。関数をリストに適用するとどうなりますか?

リストもファンクターです! 定義は次のとおりです。
instance Functor [] where fmap = map
わかりました、わかりました、もう1つ(最後の)例:関数を別の関数に適用するとどうなりますか?
fmap (+3) (+1)
関数は次のとおりです。

そして、これは別の関数に適用される関数です:

結果は単なる別の機能です!
> import Control.Applicative > let foo = fmap (+3) (+2) > foo 10 15
関数もファンクターです!
instance Functor ((->) r) where fmap fg = f . g
また、関数に
fmap
を適用すると、関数を作成するだけです!
応用ファンクター
次のレベルは、アプリカティブファンクターです。 それらによって、私たちの価値はまだコンテキストに詰め込まれています(ファンクターの場合と同様):

しかし今、私たちの関数はコンテキストに詰め込まれています!

うん! これを始めましょう。 応用ファンクターは詐欺に関与しません。
Control.Applicative
は、 コンテキストでパッケージ化された関数をコンテキストで パッケージ化された値に適用する方法を知っている
<*>
を定義します 。

つまり
Just (+3) <*> Just 2 == Just 5
<*>
を使用すると、興味深い状況につながる可能性があります。 例:
> [(*2), (+3)] <*> [1, 2, 3] [2, 4, 6, 4, 5, 6]

そして、ここにあなたが適用可能なファンクターの助けを借りてできることがありますが、普通のファンクターの助けを借りてはできません。 2つの引数を2つのパック値に取る関数をどのように適用しますか?
> (+) <$> (Just 5) Just (+5) > Just (+5) <$> (Just 4) ??? JUST
適用可能なファンクター:
> (+) <$> (Just 5) Just (+5) > Just (+5) <*> (Just 3) Just 8
Applicative
Functor
を技術的に押しのけます。 「大物は、任意の数の引数を持つ関数を使用できます」と彼は言います。 「
<$>
と
<*>
で武装しているので、任意の数のアンパックされた引数を予期する関数を使用できます。 次に、すべてのパックされた値を彼女に渡し、パックされた結果を取得します! BWAHAHAHAHAHA!」
> (*) <$> Just 5 <*> Just 3 Just 15

応用ファンクタは、正規関数がどのように関数を適用するかを観察します
そしてはい! 同じことを行う
liftA2
関数があります。
> liftA2 (*) (Just 5) (Just 3) Just 15
モナド
モナドを学ぶ方法:
- コンピューターサイエンスで博士号を取得
- このセクションを読むときにそれらは必要ないので、彼らにnafigを投げてください!
モナドはプロットに新しいひねりを加えます。
ファンクターは、パックされた値に通常の関数を適用します。

適用可能なファンクターは、パック関数をパック値に適用します。

モナドは、パックされた値をパックされた値に戻す関数を適用します。 モナドには関数
>>=
(「バインディング」と発音します( バインド ))があり、これを行うことができます。
この例を考えてみましょう:私たちの古き良き
Maybe
はモナドです:

ぶら下がりモナド
half
を偶数でのみ機能する関数とします。
half x = if even x then Just (x `div` 2) else Nothing

しかし、パックされた値を彼女に与えるとどうなりますか?

関数でパックされた値をプッシュするには、
>>=
を使用する必要があります。 写真はこちら
>>=
:

そして、これがどのように機能するかです:
> Just 3 >>= half Nothing > Just 4 >>= half Just 2 > Nothing >>= half Nothing
内部で何が起こっているのですか?
Monad
は別の型クラスです。 部分的な定義は次のとおりです。
class Monad m where (>>=) :: ma -> (a -> mb) -> mb
ここで
>>=
:

だから
Maybe
モナドです:
instance Monad Maybe where Nothing >>= func = Nothing Just val >>= func = func val
しかし、貧しい
Just 3
に対してどのようなアクションが行われているのでしょうか。

入力に
Nothing
を渡すと、さらに簡単になります。

一連の呼び出しをリンクすることもできます。
> Just 20 >>= half >>= half >>= half Nothing


かっこいい! そして今、
Maybe
が
Functor
、
Applicative
、そして
Monad
1つになっていることがわかりました。
それでは、別の例に切り替えましょう:
IO
モナド:

特に、3つの機能。
getLine
は引数を取らず、入力からユーザーデータを受け取ります。

getLine :: IO String
readFile
は文字列(ファイル名)を取り、その内容を返します。

readFile :: FilePath -> IO String
putStrLn
は文字列を取り、それを出力します:

putStrLn :: String -> IO ()
3つの関数はすべて、通常の値(または値なし)を取り、パックされた値を返します。 したがって、
>>=
を使用してそれらをチェーンできます!

getLine >>= readFile >>= putStrLn
はい、モナドショーの最前列のチケットがあります!
Haskellは、
do
記法と呼ばれるモナドの構文糖衣も提供します。
foo = do filename <- getLine contents <- readFile filename putStrLn contents
おわりに
- ファンクターは、
Functor
型クラスを使用して実装されるデータ型です - Applicative Functorは、
Applicative
型クラスを使用して実装されるデータ型です - Monadは、
Monad
型クラスを使用して実装されるデータ型です。 - 3種類すべてのタイプを使用して実装される可能性があるため、同時にファンクター、適用ファンクター、およびモナドです
3つの違いは何ですか?

- functor :
fmap
または<$>
を使用して、パックされた値に関数を適用します - applicative functor :
<*>
またはliftA
を使用して、パックされた値にパックされた関数を適用します -
liftM
>>=
またはliftM
を使用して、パックされた値をパックされた値に返す関数を適用します
だから、親愛なる友人(そして、この瞬間までに友人になったことを願っています)、私はモナドがシンプルでスマートなアイデア(tm)であることに全員が同意すると思います。 そして今、このガイドで喉を濡らした後、メルギブソンに電話してボトルを仕上げてみませんか? LYAHのモナドセクションをご覧ください。 Miranがこの資料を深める素晴らしい仕事をしてくれたので、私が言及しなかったことがたくさんあります。
さらに多くのモナドと写真が3つの便利なモナドにあります ( 翻訳 )。
翻訳者から:
オリジナルへのリンク: http ://adit.io/posts/2013-04-17-functors,_applicatives,_and_monads_in_pictures.html HabrはURLをカンマで誓うので、このように書きます。
そしてもちろん、翻訳に関するPMのコメントに非常に感謝します。