F# Active Pattern List.filter 或等效项
我有一个类型的记录
type tradeLeg = {
id : int ;
tradeId : int ;
legActivity : LegActivityType ;
actedOn : DateTime ;
estimates : legComponents ;
entryType : ShareOrDollarBased ;
confirmedPrice: DollarsPerShare option;
actuals : legComponents option ;
type trade = {
id : int ;
securityId : int ;
ricCode : string ;
tradeActivity : TradeType ;
enteredOn : DateTime ;
closedOn : DateTime ;
tradeLegs : tradeLeg list ;
}
显然,tradeLegs 是交易的一种类型。一条边可能已结算或未结算(或未结算但价格已确认) - 因此我定义了活动模式:
let (|LegIsSettled|LegIsConfirmed|LegIsUnsettled|) (l: tradeLeg) =
if Helper.exists l.actuals then LegIsSettled
elif Helper.exists l.confirmedPrice then LegIsConfirmed
else LegIsUnsettled
然后确定交易是否已结算(基于与 LegIsSettled 模式匹配的所有边):
let (|TradeIsSettled|TradeIsUnsettled|) (t: trade) =
if List.exists (
fun l ->
match l with
| LegIsSettled -> false
| _ -> true) t.tradeLegs then TradeIsSettled
else TradeIsUnsettled
我可以看到这种使用的一些优点 模式,但是我认为有一种更有效的方法来查看列表中的任何项目是否匹配(或不匹配)actie 模式,而无需专门为其编写 lambda 表达式,并使用 List.exist。
活动 有两个方面:
- 有没有更简洁的方式来表达这个?
有没有办法抽象功能/表达式
(有趣的 l -> 将 l 与 |立法已解决 ->错误的 | _->真的)
,以便
let itemMatchesPattern pattern item =
match item with
| pattern -> true
| _ -> false
我可以编写(因为我正在重用此设计模式):
let curriedItemMatchesPattern = itemMatchesPattern LegIsSettled
if List.exists curriedItemMatchesPattern t.tradeLegs then TradeIsSettled
else TradeIsUnsettled
想法?
I have a records of types
type tradeLeg = {
id : int ;
tradeId : int ;
legActivity : LegActivityType ;
actedOn : DateTime ;
estimates : legComponents ;
entryType : ShareOrDollarBased ;
confirmedPrice: DollarsPerShare option;
actuals : legComponents option ;
type trade = {
id : int ;
securityId : int ;
ricCode : string ;
tradeActivity : TradeType ;
enteredOn : DateTime ;
closedOn : DateTime ;
tradeLegs : tradeLeg list ;
}
Obviously the tradeLegs are a type off of a trade. A leg may be settled or unsettled (or unsettled but price confirmed) - thus I have defined the active pattern:
let (|LegIsSettled|LegIsConfirmed|LegIsUnsettled|) (l: tradeLeg) =
if Helper.exists l.actuals then LegIsSettled
elif Helper.exists l.confirmedPrice then LegIsConfirmed
else LegIsUnsettled
and then to determine if a trade is settled (based on all legs matching LegIsSettled pattern:
let (|TradeIsSettled|TradeIsUnsettled|) (t: trade) =
if List.exists (
fun l ->
match l with
| LegIsSettled -> false
| _ -> true) t.tradeLegs then TradeIsSettled
else TradeIsUnsettled
I can see some advantages of this use of active patterns, however i would think there is a more efficient way to see if any item of a list either matches (or doesn't) an actie pattern without having to write a lambda expression specifically for it, and using List.exist.
Question is two fold:
- is there a more concise way to express this?
is there a way to abstract the functionality / expression
(fun l -> match l with | LegIsSettled -> false | _ -> true)
Such that
let itemMatchesPattern pattern item =
match item with
| pattern -> true
| _ -> false
such I could write (as I am reusing this design-pattern):
let curriedItemMatchesPattern = itemMatchesPattern LegIsSettled
if List.exists curriedItemMatchesPattern t.tradeLegs then TradeIsSettled
else TradeIsUnsettled
Thoughts?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
为了回答您有关活动模式的问题,让我使用一个更简单的示例:
当您使用
(|Odd|Even|)
声明具有多个选项的模式时,编译器会将其理解为返回的函数Choice
类型的值。因此,您可以使用的活动模式是整个组合|Odd|Even|
而不仅仅是您可以独立使用的两个构造(例如|Odd|
和|偶数|
)。可以将活动模式视为第一类函数,但如果您使用具有多个选项的模式,则不能用它做太多事情:
您可以编写函数来测试一个值是否与指定模式匹配,但是您需要很多函数(因为有许多
Choice
类型因类型参数的数量而重载):像这样适合你的情况,但它远非完美。
如果声明多个部分活动模式,您可以做得更好一些(但是您当然会失去完整活动模式的一些好的方面,例如完整性检查):
现在您可以编写一个函数来检查值是否与模式匹配:
总结 虽然可能有一些或多或少优雅的方式来实现您所需要的,但我可能会考虑活动模式是否为您提供比使用标准函数更大的优势。首先使用函数来实现代码,然后决定哪些构造可用作活动模式,然后再添加活动模式,这可能是一个更好的主意。在这种情况下,通常的代码看起来不会更糟糕:
To answer your question about active patterns, let me use a simpler example:
When you declare a pattern that has multiple options using
(|Odd|Even|)
, then the compiler understands it as a function that returns a value of typeChoice<unit, unit>
. So, the active pattern that you can work with is the whole combination|Odd|Even|
and not just two constructs that you could use independently (such as|Odd|
and|Even|
).It is possible to treat active patterns as first class functions, but if you're using patterns with multiple options, you cannot do much with it:
You can write function that tests whether a value matches a specified pattern, but you'd need a lot of functions (because there are many
Choice
types overloaded by the number of type parameters):Something like this would work in your case, but it is far from being perfect.
You can do a little better job if you declare multiple partial active patterns (but then you of course loose some nice aspects of full active patterns such as completeness checking):
Now you can write a function that checks whether a value matches pattern:
Summary While there may be some more or less elegant way to achieve what you need, I'd probably consider whether active patterns give you any big advantage over using standard functions. It may be a better idea to implenent the code using functions first and then decide which of the constructs would be useful as active patterns and add active patterns later. In this case, the usual code wouldn't look much worse:
除了 Tomas 关于活动模式实际细节的观点之外,请注意,您始终可以缩短
fun x ->;将 x 与 |...
匹配到function | ...
,这将节省一些击键次数,并且无需编写可能无意义的标识符。In addition to Tomas's points on the actual details of active patterns, note that you can always shorten
fun x -> match x with |...
tofunction | ...
, which will save a few keystrokes as well as the need to make up a potentially meaningless identifier.