- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
F# 的“选项”似乎是一种使用类型系统将已知存在的数据与可能存在或不存在的数据分开的好方法,而且我喜欢 match
表达式的方式强制考虑所有情况:
match str with
| Some s -> functionTakingString(s)
| None -> "abc" // The compiler would helpfully complain if this line wasn't present
s
(与str
相对)是一个字符串
而不是字符串选项
,这一点非常有用。
但是,在处理具有可选字段的记录时...
type SomeRecord =
{
field1 : string
field2 : string option
}
...并且这些记录正在被过滤,match
表达式感觉没有必要,因为在 None
情况下没有任何明智的做法,但是这个...
let functionTakingSequenceOfRecords mySeq =
mySeq
|> Seq.filter (fun record -> record.field2.IsSome)
|> Seq.map (fun record -> functionTakingString field2) // Won't compile
...无法编译,因为虽然field2
未填充的记录已被过滤掉,但field2
的类型仍然是string选项
,而不是字符串
。
我可以定义另一种记录类型,其中 field2
不是可选的,但这种方法看起来很复杂,并且可能不适用于许多可选字段。
我定义了一个运算符,如果选项为 None
...,则该运算符会引发异常...
let inline (|?!) (value : 'a option) (message : string) =
match value with
| Some x -> x
| None -> invalidOp message
...并将之前的代码更改为这个...
let functionTakingSequenceOfRecords mySeq =
mySeq
|> Seq.filter (fun record -> record.field2.IsSome)
|> Seq.map (fun record -> functionTakingString (record.field2 |?! "Should never happen")) // Now compiles
...但这似乎并不理想。我可以使用 Unchecked.defaultof
而不是引发异常,但我不确定这是否更好。其关键在于 None
情况在过滤后不相关。
有没有更好的方法来处理这个问题?
编辑
非常有趣的答案引起了我对记录模式匹配的注意,这是我没有意识到的,还有 Value
,我见过但误解了它(我看到它抛出了 >NullReferenceException
(如果无
)。但我认为我的例子可能很糟糕,因为我更复杂的现实问题涉及使用记录中的多个字段。我怀疑我陷入了类似的困境......
|> Seq.map (fun record -> functionTakingTwoStrings record.field1 record.field2.Value)
除非还有别的事吗?
最佳答案
在此示例中,您可以使用:
let functionTakingSequenceOfRecords mySeq =
mySeq
|> Seq.choose (fun { field2 = v } -> v)
|> Seq.map functionTakingString
Seq.choose
允许我们根据可选结果过滤项目。在这里,我们对记录进行模式匹配以获得更简洁的代码。
我认为总体思路是使用组合器、高阶函数来操作选项值,直到您想将它们转换为其他类型的值(例如,在本例中使用 Seq.choose
)。不鼓励使用 |?!
因为它是部分运算符(在某些情况下会引发异常)。您可以说在这种特殊情况下使用它是安全的;但 F# 类型系统无法检测到它并在任何情况下警告您有关不安全使用的情况。
顺便说一句,我建议您查看面向铁路的编程系列:http://fsharpforfunandprofit.com/posts/recipe-part2/ 。该系列向您展示了处理错误的类型安全且可组合的方法,您可以在其中保留诊断信息。
更新(根据您的编辑):
函数的修订版本编写如下:
let functionTakingSequenceOfRecords mySeq =
mySeq
|> Seq.choose (fun { field1 = v1; field2 = v2 } ->
v2 |> Option.map (functionTakingString v1))
它演示了我提到的一般思想,即使用高阶函数 (Option.map
) 操作选项值并在最后一步 (Seq.choose
) 转换它们)。
关于F# 对具有可选字段的记录进行模式匹配,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28090247/
我正在尝试用 Swift 编写这段 JavaScript 代码:k_combinations 到目前为止,我在 Swift 中有这个: import Foundation import Cocoa e
我是一名优秀的程序员,十分优秀!