5

基本的にStateモナドを実装する計算式を作成していて、式を使用しようとしていますfor

ボイラープレート関数forLoopまたはを使用することもできますが、それらはすべて、さらに式で処理できるMBuilder.For()素敵なものを返します。しかし、式で同じことをしようとすると、コンパイルに失敗し、内部の式はを返す必要があることを通知します。M<seq<'U>, _>let!forforunit

小さくできない大きなコードブロックでごめんなさい。

type M<'T, 'E> = 'T * 'E                 // Monadic type is a simple tuple
type MFunc<'T, 'U, 'E> = 'T -> M<'U, 'E> // A function producing monadic value

// typical boilerplate functions
let bind (x: M<'T, 'E>) (f: MFunc<'T, 'U, 'E>) : M<'U, 'E> =
    let a, s = x
    let b, s1 = f a
    b, s1 + s
let combine (e1: M<'T, 'E>) (e2: M<'U, 'E>) : M<'U, 'E> = bind e1 (fun _ -> e2)
let delay f = (fun () -> f())()

// These two are explained below
let combineList (e1: M<'T, 'E>) (e2: M<'T seq, 'E>) : M<'T seq, 'E> =
    bind
        e1
        (fun x1 ->
            let e2body, e2state = e2
            seq{yield! e2body; yield x1}, e2state
        )
let forLoop (xs: seq<'T>) (f: MFunc<'T, 'U, 'E>) : M<seq<'U>, 'E> =
    Seq.fold
        (fun s x -> combineList (f x) s)
        (Seq.empty<'U>, 0)
        xs

// Builder class
type MBuilder() =
    member this.Bind (x: M<'T, 'E>, f: MFunc<'T, 'U, 'E>) : M<'U, 'E> = bind x f
    member this.Return(a) = a, 0
    member this.Combine(e1,e2) = combine e1 e2
    member this.Delay(f) = delay f
    member this.Zero() = (), 0
    member this.For (xs: seq<'T>, f: MFunc<'T, 'U, 'E> ) : M<seq<'U>, 'E> = forLoop xs f
let stateful = new MBuilder()

let mTest = stateful {
    // below is the typical use, just for example
    let! var1 = "q", 3
    let! var2 = true, 4
    // so far so good, the monad returns ("test", 7)
    return "test"
    }

今、私はループを使おうとしています。次の3つの呼び出しは期待どおりに機能し、の要素の数だけ状態をインクリメントしますmyList。彼らはまたstring seq、明らかに最後の呼び出しを除いて、美しいものを返します:

    let myList = ["one"; "two"; "three"] // define test data

    let! var3 = stateful.For(myList, (fun x -> x, 1))
    let! var4 = forLoop myList (fun x -> x, 1)

    // No return value, as expected
    for str in myList do
        let! _ = str, 1
        return ""

ただし、以下はコンパイルされません。error FS0001: This expression was expected to have type M<'a,int> but here has type unit

    let! var5 =
        for str in myList do
            let! _ = str, 1
            return ""

だから私の質問は-私は何を間違っているのですか?

また、ここForで説明する2つのオーバーロードと、両方の使用方法について少し混乱しています。

4

1 に答える 1

11

記述しようとしているコードは、構文的に有効な計算式ではありません。e構文では、の式に計算式の構成を含めることはできませんlet! v = e

ネストされた計算式を使用する場合は、次のように記述する必要があります。

let mtest = stateful {
  let! var5 = 
    stateful { for str in myList do 
                 let! _ = str, 1 
                 return "" }
  return "something here" }

これはあなたの当面の質問に答えるはずですが、あなたの定義について私がかなり混乱していると思うことがいくつかあります。

  • あなたのタイプForは紛らわしいです。seq<'T> -> ('T -> M<'R>) -> M<'R>(モナドが複数の結果を組み合わせることができる場合)またはseq<'T> -> ('T -> M<unit>) -> M<unit>(計算が単一の値のみを返す場合)のいずれかである必要があります

  • 結果(in )でseq<'T>insideを使用している場合もありますが、モナドが1つの値のみを返す場合もあります。どこでも同じモナディックタイプを使用する必要があります。M<_>For

  • 構成は、およびForで定義できます。何か特別なことをしているのでない限り、それが最善の方法です。F#仕様の例を参照してください。ZeroCombine

より詳細なドキュメントが必要な場合は、さまざまなオプションについて説明しているこの記事を参照してください。

于 2012-06-28T20:51:17.920 に答える