9

私はちょうどモナド(少なくとも私は持っていると思いたい)とより具体的には状態モナドに頭を包み込みました。 .

とにかく、状態モナドは通常、次のような M<'a> で実装されます (F#):

type State<'a, 'state> = State of ('state -> 'a * 'state)

ここで私の質問: ここでタプルを使用できない理由はありますか? MonadA<'a, 'b>それ以外の場合、とwhichの間のあいまいさの可能性は、MonadB<'a, 'b>両方とも同等の('a * 'b)タプルになります。

編集:わかりやすくするために例を追加

type StateMonad() =
  member m.Return a = (fun s -> a, s)
  member m.Bind(x, f) = (fun s -> let a, s_ = x s in f a s_)

let state = new StateMonad()
let getState = (fun s -> s, s)
let setState s = (fun _ -> (), s) 
let execute m s = m s |> fst
4

3 に答える 3

15

State モナドは基本的に typeで動作します。これは、何らかの初期状態を取り、(状態の新しい値と共に) 結果を生成'state -> 'res * 'stateする計算を表します。

この型に特別な名前を付けるかどうか (例: State<'state, 'res>) に違いがあるかどうかを尋ねている場合、その答えは、実際には問題ではないということです。型に特別な名前を付ける唯一の目的は、コードを読みやすくすることです。たとえば、次の例で考えられる 2 つの型シグネチャを見てみましょう。

let foo n = state {
  let! m = getState()
  do! setState(m + 1)
  return sprintf "Result: %d" (n * m) }

// Using State<'state, 'res> type:
val foo : int -> State<int, string>

// Using the underlying representation:
val foo : int -> int -> int * state

最初の型シグネチャは、モナドに関数を書いていることをより明確に示しています。2 番目の例は、2 つの値を取る単なる関数intです。最初のものの主な利点は、型が他のモナド計算 (を使用して記述) から使用できることをより簡単に認識できることだと思いますstate { ... }

ただし、既に述べたように、これは技術的な要件ではありません。多くのモナドは Haskell から来ており、モナドは計算ビルダー( など) ではなく( など)に関連付けられているため、人々はおそらくこのスタイルを使用します。ハスケル。State<'state, 'res>state

于 2010-04-07T21:13:50.030 に答える
7

あなたの例のモナド値の型は単なるタプルではありません - それはタプルを返す関数です:

'state -> 'res * 'state

'state * 'resモナド計算の型として使用できるかどうかを尋ねている場合、答えはノーです。次の型シグネチャが必要な return 操作を (安全に) 実装する方法がないため、これは機能しません。

// how would we get a value of type 'state in the implementation?
val return : 'a -> 'state * 'a
于 2010-04-07T21:17:04.647 に答える
5

Ah, yes, if the question is: should I use a single-tag Discriminated Union that carries a data value of type T, or should I just use T, then you can use either.

In Haskell, you need to use a data tag with monads, since the Haskell do syntax infers the monad type based on value types (a tuple representation could be an instance of at most a single Monad). Whereas in F#, computation expressions are explicit about the monad type (e.g. state { ... } or async { ... } or whatever) so this restriction is not necessary, the same representation type could be used for multiple monads.

于 2010-04-07T21:13:06.140 に答える