你可以如何创建一个适用于从命令式库返回布尔值的 Option.bind?

huangapple go评论48阅读模式
英文:

How can you make an Option.bind but for bool returns from an imperative library?

问题

以下是您要求的代码的翻译部分:

// 使用函数风格的命令式库
// y 是一个 outref,但定义为 byref<'T>。您必须定义一个可变变量来获取输出。您不能使用:let boolRes, y = CreateY x
let CreateY (x, y: byref<'T>) = 
    if x > 0 then 
        y <- x
        true
    else false

// 我的代码
// 如果为真则继续
// 我无法让这个工作
let (|>>) f b =
    match b with
    | true -> f
    | false -> false

// 一旦我获得了所有参数,我可以执行自己的 F# 风格操作
let doSomething1 y1 y2 y3 = 
    let y4: int = y1 + y2 + y3
    printfn "我得到了 %i 和 %i 和 %i,现在我可以制作 %i" y1 y2 y3 y4
    y4

let doSomething2 y4 = 
    let y5: int = y4 * 2
    y5

let whyWontThisWork () = 
    let mutable y1 = 0
    let mutable y2 = 0
    let mutable y3 = 0

    CreateY(0, &y1)
    |>> CreateY(2, &y2)
    |>> CreateY(3, &y3)
    |>> doSomething1 y1 y2 y3 // 预期类型为 bool?
    |> doSomething2 // 预期一个 bool -> a???

请注意,我已将 HTML 实体字符(如 &amp;&gt;)还原为它们的正常文本形式。如果需要更多帮助,请告诉我。

英文:

How do you do a bind-type operation with boolean results, then switch over to an F# style pipe workflow? I don't understand why the compiler complains when I switch from the "continue if to true" |>> to using a standard pipe at the end. The output of doSomething1 isn't being passed to |>>, so why does it care what its type is?

//Function style for an imperative library.
//y is an outref but defined as byref&lt;&#39;T&gt;. You 
//have to define a mutable var to get the 
//output. You can&#39;t use: let boolRes, y = CreateY x
let CreateY (x, y: byref&lt;&#39;T&gt;) = 
    if x &gt; 0 then 
        y &lt;- x
        true
    else false

//My code
//Continue If True
//I can&#39;t get this to work
let (|&gt;&gt;) f b =
    match b with
    | true -&gt; f
    | false -&gt; false

//Once I get all my parameters, I can do my own f#
//style things.  
let doSomething1 y1 y2 y3 = 
    let y4: int = y1 + y2 + y3
    printfn &quot;I get a %i and a %i and a %i and now I can make %i&quot; y1 y2 y3 y4
    y4

let doSomething2 y4 = 
    let y5: int = y4 * 2
    y5

let whyWontThisWork () = 
    let mutable y1 = 0
    let mutable y2 = 0
    let mutable y3 = 0

    CreateY(0, &amp;y1)
    |&gt;&gt; CreateY(2, &amp;y2)
    |&gt;&gt; CreateY(3, &amp;y3)
    |&gt;&gt; doSomething1 y1 y2 y3 //expected to have type bool?
    |&gt; doSomething2 //expecting a bool -&gt; a???

答案1

得分: 1

以下是您提供的代码的翻译部分:

如果您愿意使用选项我认为可以通过使用计算表达式来优雅地完成这项工作

let CreateY (x, y: byref<int>) = 
    if x > 0 then 
        y <- x
        true
    else false

type Builder() =
    member _.Return(value) = Some value
    member _.ReturnFrom(opt : Option<_>) = opt
    member _.Bind(b, f) = if b then f () else None
    member _.Zero() = None

let build = Builder()

let doSomething1 y1 y2 y3 = 
    let y4: int = y1 + y2 + y3
    printfn "I get a %i and a %i and a %i and now I can make %i" y1 y2 y3 y4
    y4

let doSomething2 y4 = 
    let y5: int = y4 * 2
    y5

let thisWillWork x = 
    let mutable y1 = 0
    let mutable y2 = 0
    let mutable y3 = 0

    build {
        do! CreateY(x, &y1)
        do! CreateY(2, &y2)
        do! CreateY(3, &y3)
        return doSomething1 y1 y2 y3
            |> doSomething2
    }

thisWillWork 1 |> printfn "%A"   // Some 12
thisWillWork 0 |> printfn "%A"   // None

关键行是:

    member _.Bind(b, f) = if b then f () else None

只是为了展示正在发生的事情,这将展开为:

    build.Bind(CreateY(x, &y1), fun () ->
    build.Bind(CreateY(2, &y2), fun () ->
    build.Bind(CreateY(3, &y3), fun () ->
    doSomething1 y1 y2 y3
        |> doSomething2
        |> Some)))

希望这有所帮助!

英文:

If you're willing to use options, I think this can be done elegantly using a computation expression:

let CreateY (x, y: byref&lt;int&gt;) = 
    if x &gt; 0 then 
        y &lt;- x
        true
    else false

type Builder() =
    member _.Return(value) = Some value
    member _.ReturnFrom(opt : Option&lt;_&gt;) = opt
    member _.Bind(b, f) = if b then f () else None
    member _.Zero() = None

let build = Builder()

let doSomething1 y1 y2 y3 = 
    let y4: int = y1 + y2 + y3
    printfn &quot;I get a %i and a %i and a %i and now I can make %i&quot; y1 y2 y3 y4
    y4

let doSomething2 y4 = 
    let y5: int = y4 * 2
    y5

let thisWillWork x = 
    let mutable y1 = 0
    let mutable y2 = 0
    let mutable y3 = 0

    build {
        do! CreateY(x, &amp;y1)
        do! CreateY(2, &amp;y2)
        do! CreateY(3, &amp;y3)
        return doSomething1 y1 y2 y3
            |&gt; doSomething2
    }

thisWillWork 1 |&gt; printfn &quot;%A&quot;   // Some 12
thisWillWork 0 |&gt; printfn &quot;%A&quot;   // None

The key line is:

    member _.Bind(b, f) = if b then f () else None

Just to show what's going on, this desugars to:

    build.Bind(CreateY(x, &amp;y1), fun () -&gt;
    build.Bind(CreateY(2, &amp;y2), fun () -&gt;
    build.Bind(CreateY(3, &amp;y3), fun () -&gt;
    doSomething1 y1 y2 y3
        |&gt; doSomething2
        |&gt; Some)))

huangapple
  • 本文由 发表于 2023年5月6日 23:56:41
  • 转载请务必保留本文链接:https://go.coder-hub.com/76189831.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定