我的代码包含了不少双选项类型;到目前为止,我一直非常成功地使用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这样的东西同时作用于两个选项,但没有一个。
答案 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个论点有很多实际用途。您可以按照类似的方案实施map
,iter
或fold
的不同方面。
这不像使用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
可以取决于a
和b
,依此类推,这在应用风格中是不可能的。计算表达式语法也比使用原始运算符的应用程序更容易理解。