如何在 F# 中乘以两个(双选项)
How to multiply two (double option)s in F#
我的代码包含很多双选项类型;到目前为止,我一直在非常成功地使用 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 这样的东西来同时处理两个选项,但没有一个。
模式可以嵌套,这是它们的强大之处。在这种特殊情况下,您可以对元组进行模式匹配:
match option1, option2 with
| Some x, Some y -> Some (x * y)
| _ -> None
正确答案如下:
https://fsharpforfunandprofit.com/posts/elevated-world/#apply
如果需要一些代码,则可以归结为以下示例:
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
之所以这样说,是因为上面的方法可以在 Wlaschin 所谓的 "elevated world" 中进出,或者在这种情况下是 Option,并混合两者的东西。有点儿。阅读 Wlaschin 撰写的完整网站或书籍。
不需要做任何以Option为参数的函数,包装和解包可以一劳永逸。
正如上面的代码所示(无耻地从link偷来的,并进行了一些重写),理查德需要的功能是:
Option.apply
是的,这些符号可能会造成混淆,尤其是因为我们在这里讨论的是乘法或 *,但是映射 和应用 <*> 的这些符号有点 'standard'。
关于如何阅读代码,我认为代码中的注释或多或少是正确的。
是的,我可能需要改进我的教学风格 ;-)
您的 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
的不同参数。
这不像使用应用函子那样健壮或形式上优雅,但它解决了问题而没有引入太多概念开销。
我会选择 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
}
对
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
,等等,这在应用风格中是不可能的。计算表达式语法也比只有原始运算符的应用函子更容易理解。
我的代码包含很多双选项类型;到目前为止,我一直在非常成功地使用 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 这样的东西来同时处理两个选项,但没有一个。
模式可以嵌套,这是它们的强大之处。在这种特殊情况下,您可以对元组进行模式匹配:
match option1, option2 with
| Some x, Some y -> Some (x * y)
| _ -> None
正确答案如下:
https://fsharpforfunandprofit.com/posts/elevated-world/#apply
如果需要一些代码,则可以归结为以下示例:
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
之所以这样说,是因为上面的方法可以在 Wlaschin 所谓的 "elevated world" 中进出,或者在这种情况下是 Option,并混合两者的东西。有点儿。阅读 Wlaschin 撰写的完整网站或书籍。
不需要做任何以Option为参数的函数,包装和解包可以一劳永逸。
正如上面的代码所示(无耻地从link偷来的,并进行了一些重写),理查德需要的功能是:
Option.apply
是的,这些符号可能会造成混淆,尤其是因为我们在这里讨论的是乘法或 *,但是映射 和应用 <*> 的这些符号有点 'standard'。
关于如何阅读代码,我认为代码中的注释或多或少是正确的。
是的,我可能需要改进我的教学风格 ;-)
您的 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
的不同参数。
这不像使用应用函子那样健壮或形式上优雅,但它解决了问题而没有引入太多概念开销。
我会选择 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
}
对
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
,等等,这在应用风格中是不可能的。计算表达式语法也比只有原始运算符的应用函子更容易理解。