Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Activity
    bleis-tift
    @bleis-tift
    asyncは単なるコンピュテーション式なので、専用ロジックとかはないはず
    seqもデシュガー(といっていいのか?)後に汎用の最適化がかかる可能性はあるかもしれないですけど、専用の最適化とかはなかった気がします
    queryも単なるコンピュテーション式なので同様
    独自のAsyncBuilderを定義するのは普通に可能です
    omanuke
    @omanuke
    なるー
    KURATA Sayuri
    @sayurin
    AsyncBuilderを前提に独自の拡張メソッドを定義してasync{}から使えますしね
    Kouji Matsui
    @kekyo
    あ、確かに #自分でやってて忘れてた
    AsyncBiulderはここで定義されてます
    pocketberserker
    @pocketberserker
    標準のAsyncBuilderはSealedクラスで継承できないので、基本ラップする方針になりやすいですね
    https://github.com/pocketberserker/ComputationExpressions/blob/452d77b7be97cbae2ed022c0273629e214223a62/src/ComputationExpressions/Async.fs#L8
    ここからの流れだ
    発言にリンクできないのかな・・・
    こうか?
    あ、%Aの話です
    bleis-tift
    @bleis-tift
    XmlDocumentを%Aした結果が腐ってる、という話だったようですね
    bleis-tift
    @bleis-tift
    コンピュテーション式やseq式を調べたときに読んだ構成から現在の実装がかけ離れている・・・
    かなーり大胆に変更されているなこれ
    とりあえず、seq式は型無しのAST時点ではApp(..., Ident seq, CompExpr(...))みたいな感じにパースされることが分かった
    これは、asyncビルダーとかと同じパースのされ方なので、コンピュテーション式扱いっぽい
    実際に走査しているのはここですかね

    note: sequence expressions use SynExpr.CompExpr too - they need to be filtered out

    なんてコメントがあります

    callmekohei
    @callmekohei

    <リストモナドに関して>

    度々すみません。お手すきのときにでも。。。
    以前、x y zを足して7になるリストを求めたいとのことで書いたのですが、ブレイスさんの回答をみて、これはモナドでは?と思い、書いてみました!多分これでいいと思うのですが、合計で7になるのが取り出せません。なにか良いアイディアあればお願いします。またモナドの勉強を始めたばかりなので間違ってたらご指摘してもらえると嬉しいです(^_^)/
    module Test_ListMonad =
    
        type ListBuilder () =
            member this.Bind (m, f) = m |> List.collect f
            member this.Return x =  [x]
            member this.ReturnFrom x = x
    
        let lb = ListBuilder()
    
        let lessThan n  = [1..n]
        let plusMinus a b c = [a, b, c]
    
        let allPMs l m n = lb {
            let! x = lessThan l
            let! y = lessThan m
            let! z = lessThan n
            return! plusMinus x y z
        }
    
        allPMs 6 6 6 |> printfn "%A"
    bleis-tift
    @bleis-tift
    Zero,Delay,Runを定義すればコンピュテーション式でいけると思います。
    ただ、そうした場合、モナドよりも表現力の高いモナドプラスなどと呼ばれるものですね
    あー、Combineも必要です
    callmekohei
    @callmekohei
    なるどです!コンピュテーション式内でいけるのですね!ちょっとやってみます!ありがとうございます!(^_^)/
    callmekohei
    @callmekohei
    うーん、先ほどのコードに足すとできるのですが、、これではないですよね(汗)
            member this.Delay f = 
                let tplsum (a, b, c) = a + b + c
                let idx = f () |> List.map ( fun tpl -> tplsum tpl )
                ( idx, f () )
                ||> List.zip 
                |> List.filter ( fun tpl -> fst tpl = 7 )
                |> List.map ( fun elm -> snd elm )
    callmekohei
    @callmekohei
    うーん、先ほどのコードに足すとできるのですが、、これではないですよね(汗)その2
            member this.Bind (x, f) = 
                let tplsum (a, b, c) = a + b + c
                let idx = ( x |> List.collect f)  |> List.map ( fun tpl -> tplsum tpl )
                ( idx, ( x |> List.collect f) )
                ||> List.zip 
                |> List.filter ( fun tpl -> fst tpl = 7 )
                |> List.map ( fun elm -> snd elm )
    callmekohei
    @callmekohei
    できました〜。let plusMinus a b c = [a; b; c]にてリストにしたらシンプルになりました!delayとか使う方法はよくわからなかったです(汗)
    module Test_ListMonad =
    
        type ListBuilder () =
            member x.Bind (l, f) = l |> List.collect f
            member x.ReturnFrom l =
                match List.sum l with
                | 7 -> [l] | _ -> []
    
        let lb = new ListBuilder()
        let lessThan n  = [1..n]
        let plusMinus a b c = [a; b; c] // <---ここが [a,b,c] tupleだったため扱いにくかった
    
        let allPMs l m n = lb {
            let! x = lessThan l
            let! y = lessThan m
            let! z = lessThan n
            return! plusMinus x y z }
    
        allPMs 6 6 6 |> printfn "%A"
    callmekohei
    @callmekohei
    今日の教訓
    [1,2,3]とするともれなくタプルで囲まれる
    [1,2,3] |> printfn "%A"
    // [(1, 2, 3)]
    
    [1;2;3] |> printfn "%A"
    // [1; 2; 3]
    bleis-tift
    @bleis-tift
    コンピュテーション式のビルダーに特殊なケースのみに使うロジックは入れるべきではありません。
    今回の場合だと、7という数字をビルダー側に書くべきではないです。
    callmekohei
    @callmekohei
    ブレイスさん!おはようございます!なるほどです!(^_^)/
    callmekohei
    @callmekohei
    なんどもすみません、、、。こんな感じでできました!
    module Test_ListMonad =
    
        type ListBuilder () =
            member x.Yield v = [v]
            member x.Bind (l, f) = l |> List.collect f
    
        let lb = new ListBuilder()
    
        let listAll =
            lb { let! x = [1..6]
                 let! y = [1..6]
                 let! z = [1..6]
                 yield [x;y;z]
                 |> fun l -> match List.sum l with 7 -> l | _ -> []
            } 
            |> List.filter ( fun l -> l <> [] ) // ここがちょっと泥臭い気が、、、
            |> printfn "%A"
    bleis-tift
    @bleis-tift
    コンピュテーション式の中でifを使って7以外を弾くといいですよ
    elseのないifを使うために、Zeroが必要です。また、その後ろに式を続ける場合はCombine(とDelayとRun)が必要です。
    bleis-tift
    @bleis-tift
    else付きのifを使ってReturnFromで空リストを返してもいいですが、コンピュテーション式側がちょっと冗長になってしまうので、定型コードはできればビルダー側に寄せたいです。
    bleis-tift
    @bleis-tift
    多分、モナドを作るところよりも先にモナドを使う方を勉強したほうがいいと思いますよ
    open FSharpPlus
    
    let listAll =
      monadPlus {
        let! x = [1..6]
        let! y = [1..(7 - x)]
        let! z = [1..(7 - x - y)]
        if x + y + z = 7 then
          return (x, y, z)
      }
    
    [<EntryPoint>]
    let main argv =
      printfn "%A" listAll
      0
    FSharpPlusというライブラリを使うとこんな感じで書けます
    callmekohei
    @callmekohei
    ブレイスさん!ありがとうございます!
    bleis-tift
    @bleis-tift
    単にモナド(やモナドプラス)としてコンピュテーション式を使うのであれば、FSharpPlusの使い方を勉強するのがいいと思います
    omanuke
    @omanuke
    モッナード、いまだよくわからないマン(´・ω・`)
    話変わりますが、VS15からC#の中から使ってるF#の箇所にF12で飛べるようになってます?VSのおかげかReSharperのおかげかわからなくて…
    callmekohei
    @callmekohei
    なるほどです!FSharpPlusですね!(^_^)/
    bleis-tift
    @bleis-tift
    VS15をまだ入れてないw
    VSデフォルトでC#からF#に飛べるなら使い勝手かなり上がりますね
    あと、モナド自体は俺もよくわからんです!