如何在F#中乘以两个(双选项)s

时间:2016-08-22 14:54:34

标签: f# monads

我的代码包含了不少双选项类型;到目前为止,我一直非常成功地使用Option.map函数,无需在所有地方匹配Some和None,并将它们视为提升类型,但我不确定在以下场景中该怎么做:

let multiplyTwoOptions option1 option2 : double option =
  if not (option1.IsSome && option2.IsSome) then None
  else Some (option1.Value * option2.Value)

read你不应该以这种方式使用IsSome,但另一种选择(据我所知,顺序上的模式匹配,似乎很长时间)。我对F#还是很陌生,所以想知道是否有更惯用的方式?我觉得我可能需要像Option.fold2这样的东西同时作用于两个选项,但没有一个。

4 个答案:

答案 0 :(得分:10)

模式可以嵌套,这是它们的强大力量。在这种特殊情况下,您可以在元组上进行模式匹配:

match option1, option2 with
| Some x, Some y -> Some (x * y)
| _ -> None

答案 1 :(得分:9)

正确答案实际上如下:

https://fsharpforfunandprofit.com/posts/elevated-world/#apply

如果需要一些代码,那么归结为以下示例:

mysql_upgrade

说这个的原因是,上面的内容可以在Wlaschin称之为“高架世界”或者在这种情况下选项中,并且可以混合来自两者。的种类。阅读Wlaschin撰写的完整网站或书籍。

没有必要将选项作为参数进行任何功能,并且可以一劳永逸地处理包装和展开。

如上面的代码所示(从链接中无耻地被盗,并且有些重写),理查德需要的功能是:

module Option =

    // The apply function for Options
    let apply fOpt xOpt = 
        match fOpt,xOpt with
        | Some f, Some x -> Some (f x)
        | _ -> None


let (<!>) = Option.map
let (<*>) = Option.apply

let a = Some(4)
let b = Some(5)

let  multiplication = (*)

//Some multiplication function applied on a and resulting function applied on b
let res1 = Some(multiplication) <*> a <*> b
let res2 = Some(*) <*> a <*> b

//Map a onto multiplication function and resulting function applied on b
let res3 = multiplication <!> a <*> b
let res4 = (*) <!> a <*> b


val res1 : int option = Some 20
val res2 : int option = Some 20
val res3 : int option = Some 20
val res4 : int option = Some 20

//The following is without any options to try to clarify the above

let op = (*) //multiplication
//let partialRes = (*) 4
let partialRes = op 4 //make function for multiplying param with 4
let fullres = partialRes 5 //use function for multiplying with 4

val op : (int -> int -> int)
val partialRes : (int -> int)
val fullres : int = 20

是的,这些符号可能会混淆,因为我们正在讨论乘法或*这里,但这些符号用于map&lt;!&gt;并申请&lt; *&gt;有点'标准'。

我认为代码中的注释在如何阅读代码方面或多或少是正确的。

是的,我可能需要研究我的教学风格; - )

答案 2 :(得分:3)

您的fold2想法并非落空。即使它不是标准库的一部分,您也可以自己轻松实现这些功能。

这是bind2

module Option =
    let bind2 f a b =
        match a, b with
        | Some a, Some b -> f a b
        | _, _ -> None 

我已经看过bind3,但这可能会延长它。我怀疑超过3个论点有很多实际用途。您可以按照类似的方案实施mapiterfold的不同方面。

这不像使用applicative functor那样强大或正式优雅,但它解决了这个问题而没有引入太多的概念开销。

答案 3 :(得分:3)

我选择了match,但作为替代方案,您还可以使用https://www.nuget.org/packages/FSharpx.Extras/中的maybe表达式

let multiplyTwoOptions option1 option2 : double option =
  maybe {
    let! x = option1
    let! y = option2
    return x * y
  }

虽然对于一组已知的输入match更为直接,但您会注意maybe表达式对于更长的临时表达式更好:

maybe {
  let! a = getAOption()
  let! b = getBOption a
  let! c = getCOption a b
  return! getFinalOption a b c
}

VS

match getAOption() with
| None -> None
| Some a ->
  match getBOption a with
  | None -> None
  | Some b -> 
    match getCOption a b with
    | None -> None
    | Some c -> getFinalOption a b c

这也优于应用仿函数风格。生成b的函数可以取决于a,而c可以取决于ab,依此类推,这在应用风格中是不可能的。计算表达式语法也比使用原始运算符的应用程序更容易理解。