web-dev-qa-db-ja.com

無料のモナドとは何ですか?

用語Free Monadpop up everynowandthen しばらくの間、誰もが彼らが何であるかを説明することなくそれらを使用/議論しているようです。だから、無料のモナドとは何ですか? (私はモナドとHaskellの基本に精通していると思いますが、カテゴリ理論の非常に大まかな知識しかありません。)

343
David

エドワード・クメットの答えは明らかに素晴らしい。しかし、それは少し技術的です。これは、おそらくよりアクセスしやすい説明です。

無料のモナドは、ファンクターをモナドに変える一般的な方法です。つまり、任意のファンクターfFree fはモナドです。一対の関数を取得する以外は、これはあまり役に立ちません

liftFree :: Functor f => f a -> Free f a
foldFree :: Functor f => (f r -> r) -> Free f r -> r

これらの最初のものは、あなたのモナドに「入る」ことを可能にし、2番目のものは、それから「出る」方法を与えます。

より一般的には、Xが余分なものPを含むYである場合、「フリーX」は何も余分に得ることなくYからXに到達する方法です。

例:モノイド(X)は、基本的に操作(追加を考えることができる)と何らかのアイデンティティ(ゼロなど)があると言う追加の構造(P)を持つセット(Y)です。

そう

class Monoid m where
   mempty  :: m
   mappend :: m -> m -> m

今、私たちはすべてリストを知っています

data [a] = [] | a : [a]

まあ、どんなタイプのtが与えられても、[t]はモノイドであることを知っています

instance Monoid [t] where
  mempty   = []
  mappend = (++)

したがって、リストはセット(またはHaskellタイプ)の「無料モノイド」です。

さて、無料のモナドも同じ考えです。ファンクタを取り、モナドを返します。実際、モナドはエンドファンクターのカテゴリーのモノイドとして見ることができるため、リストの定義

data [a] = [] | a : [a]

無料のモナドの定義によく似ています

data Free f a = Pure a | Roll (f (Free f a))

Monadインスタンスは、リストのMonoidインスタンスと類似しています

--it needs to be a functor
instance Functor f => Functor (Free f) where
  fmap f (Pure a) = Pure (f a)
  fmap f (Roll x) = Roll (fmap (fmap f) x)

--this is the same thing as (++) basically
concatFree :: Functor f => Free f (Free f a) -> Free f a
concatFree (Pure x) = x
concatFree (Roll y) = Roll (fmap concatFree y)

instance Functor f => Monad (Free f) where
  return = Pure -- just like []
  x >>= f = concatFree (fmap f x)  --this is the standard concatMap definition of bind

今、私たちは2つの操作を取得します

-- this is essentially the same as \x -> [x]
liftFree :: Functor f => f a -> Free f a
liftFree x = Roll (fmap Pure x)

-- this is essentially the same as folding a list
foldFree :: Functor f => (f r -> r) -> Free f r -> r
foldFree _ (Pure a) = a
foldFree f (Roll x) = f (fmap (foldFree f) x)
270
Philip JF

さらに簡単な答えがあります。モナドは、join :: m (m a) -> m aによってモナドコンテキストが折りたたまれたときに「計算」されるものです(>>=x >>= y = join (fmap y x)として定義できることを思い出してください)。これは、モナドが計算の連続チェーンを通じてコン​​テキストを運ぶ方法です。シリーズの各ポイントで、前の呼び出しからのコンテキストが次のもので折りたたまれるためです。

無料のモナドはすべてのモナドの法則を満たしますが、崩壊(計算など)は行いません。ネストされた一連のコンテキストを構築するだけです。そのような無料のモナド値を作成するユーザーは、これらのネストされたコンテキストで何かを行う責任があり、そのような構成のmeaningは後まで延期することができますモナド値が作成されました。

376
John Wiegley

Free Monad(データ構造)は、Monad(クラス)に対するList(データ構造)のように、Monad(クラス)に対するものです。これは簡単な実装であり、後でコンテンツの結合方法を決定できます。


おそらく、Monadが何であるか、各Monadはfmap + join + returnまたはbind + returnの特定の(Monad-lawに従う)実装が必要であることを知っているでしょう。

Functor(fmapの実装)があると仮定しますが、残りは実行時に行われる値と選択に依存します。つまり、Monadプロパティを使用できるが、後でMonad関数を選択することを意味します。

これは、Free Monad(データ構造)を使用して行うことができます。これは、joinがリダクションではなく、それらのファンクターのスタックになるようにFunctor(タイプ)をラップします。

使用する実際のreturnおよびjoinを、リダクション関数へのパラメーターとして指定できるようになりました foldFree

foldFree :: Functor f => (a -> b) -> (f b -> b) -> Free f a -> b
foldFree return join :: Monad m => Free m a -> m a

型を説明するには、Functor fMonad mに、b(m a)に置き換えます。

foldFree :: Monad m => (a -> (m a)) -> (m (m a) -> (m a)) -> Free m a -> (m a)
61
comonad

Haskellの無料モナドはファンクターのリストです。比較:

data List a   = Nil    | Cons  a (List a  )

data Free f r = Pure r | Free (f (Free f r))

PureNilに類似しており、FreeConsに類似しています。無料のモナドは、値のリストの代わりにファンクターのリストを保存します。技術的には、異なるデータ型を使用して無料のモナドを実装できますが、どの実装も上記のものと同型でなければなりません。

抽象構文ツリーが必要なときはいつでも無料のモナドを使用します。フリーモナドの基本ファンクターは、構文木の各ステップの形状です。

私の投稿 (すでにリンクされている)は、無料のモナドで抽象的な構文ツリーを構築する方法の例をいくつか示しています

55

簡単で具体的な例が役立つと思います。ファンクターがあるとします

data F a = One a | Two a a | Two' a a | Three Int a a a

明らかなfmapで。次に、Free F aは、タイプがaであり、ノードがOneTwoTwo'およびThreeでタグ付けされているツリーのタイプです。 One- nodesには1つの子、Two-およびTwo'- nodesには2つの子、Three- nodesには3つの子があり、Intのタグも付けられています。

Free Fはモナドです。 returnは、xを、値xを持つリーフであるツリーにマップします。 t >>= fは各葉を見て、それらを木に置き換えます。リーフの値がyの場合、そのリーフをツリーf yに置き換えます。

ダイアグラムはこれを明確にしますが、簡単に描画する機能はありません!

21
Tom Ellis