List F#活动模式列表.过滤器或同等产品
我有各种类型的记录List F#活动模式列表.过滤器或同等产品,list,f#,active-pattern,List,F#,Active Pattern,我有各种类型的记录 type tradeLeg = { id : int ; tradeId : int ; legActivity : LegActivityType ; actedOn : DateTime ; estimates : legComponents ; entryType : ShareOrDollarBased ; confirmedPrice: DollarsPerShare option; actuals :
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 ;
}
显然,交易腿是交易的一种类型。一个交易段可以是已结算或未结算(或未结算但价格已确认)-因此我定义了活动模式:
let (|LegIsSettled|LegIsConfirmed|LegIsUnsettled|) (l: tradeLeg) =
if Helper.exists l.actuals then LegIsSettled
elif Helper.exists l.confirmedPrice then LegIsConfirmed
else LegIsUnsettled
然后确定交易是否已结算(基于与合法结算模式匹配的所有分支):
let (|TradeIsSettled|TradeIsUnsettled|) (t: trade) =
if List.exists (
fun l ->
match l with
| LegIsSettled -> false
| _ -> true) t.tradeLegs then TradeIsSettled
else TradeIsUnsettled
我可以看到使用活动模式的一些优点,但是我认为有一种更有效的方法可以查看列表中的任何项是否匹配(或不匹配)活动模式,而无需专门为其编写lambda表达式,并使用list.exist
问题有两个方面:
(fun l ->
match l with
| LegIsSettled -> false
| _ -> true)
let itemMatchesPattern pattern item =
match item with
| pattern -> true
| _ -> false
我可以这样写(因为我正在重用这个设计模式):
想法?要回答您关于活动模式的问题,让我用一个更简单的例子:
let (|Odd|Even|) n =
if n % 2 = 0 then Even else Odd
当您使用(|奇|偶|)
声明具有多个选项的模式时,编译器将其理解为返回类型为Choice
的值的函数。因此,您可以使用的活动模式是整个组合|奇|偶
,而不仅仅是两个可以独立使用的结构(例如|奇数|
和|偶数|
)
可以将活动模式视为第一类函数,但如果您使用具有多个选项的模式,则无法使用它:
设模式=(|奇|偶|);;
val模式:int->Choice
您可以编写测试值是否与指定模式匹配的函数,但您需要很多函数(因为有许多Choice
类型因类型参数的数量而重载):
像这样的东西在你的情况下会起作用,但它远不是完美的
如果您声明了多个部分活动模式,您可以做得更好一些(但是您当然失去了完全活动模式的一些好的方面,例如完整性检查):
现在,您可以编写一个函数来检查值是否与模式匹配:
let matches pattern value =
match pattern value with
| Some _ -> true
| None -> false
> matches (|Odd|_|) 1;;
val it : bool = true
> matches (|Even|_|) 2;;
val it : bool = true
<强>摘要<强>虽然可能有一些或多或少优雅的方式来实现您所需要的,但我可能会考虑活动模式是否比使用标准函数具有更大的优势。最好先使用函数来初始化代码,然后决定哪些结构可以作为活动模式使用。然后添加活动模式。在这种情况下,通常的代码看起来不会更糟:
type LegResult = LegIsSettled | LegIsConfirmed | LegIsUnsettled
let getLegStatus (l: tradeLeg) =
if Helper.exists l.actuals then LegIsSettled
elif Helper.exists l.confirmedPrice then LegIsConfirmed
else LegIsUnsettled
// Later in the code you would use pattern matching
match getLegStatus trade with
| LegIsSettled -> // ...
| LegIsUnSettled -> // ...
// But you can still use higher-order functions too
trades |> List.exist (fun t -> getLegStatus t = LegIsSettled)
// Which can be rewritten (if you like point-free style):
trades |> List.exist (getLegStatus >> ((=) LegIsSettled))
// Or you can write helper function (which is more readable):
let legStatusIs check trade = getLegStatus trade = check
trades |> List.exist (legStatusIs LegIsSettled)
除了Tomas关于活动模式的实际细节的观点外,请注意,您可以将
fun x->match x with |…
缩短为function |…
,这样可以节省一些击键次数,同时还可以避免编写可能毫无意义的标识符。+1:酷!我不知道您可以通过(|奇| | | |
作为一个函数的值:)当我发现这是可能的时候,我也很惊讶。实际上,活动模式有点像操作符。使用操作符你可以声明let(++)ab=a+b
并使用它们List.map(++)
。使用活动模式:let(| Xyz | |)a=None
和List.map(| Xyz |)
(名称中的空格实际上也是允许的!)谢谢你。我最初将其作为标准函数编写(尽管没有那么雄辩),并开始玩弄活动模式以释放其威力。这里有很好的信息-再次感谢你
let (|Odd|_|) n =
if n % 2 = 0 then None else Some()
let (|Even|_|) n =
if n % 2 = 0 then Some() else None
let matches pattern value =
match pattern value with
| Some _ -> true
| None -> false
> matches (|Odd|_|) 1;;
val it : bool = true
> matches (|Even|_|) 2;;
val it : bool = true
type LegResult = LegIsSettled | LegIsConfirmed | LegIsUnsettled
let getLegStatus (l: tradeLeg) =
if Helper.exists l.actuals then LegIsSettled
elif Helper.exists l.confirmedPrice then LegIsConfirmed
else LegIsUnsettled
// Later in the code you would use pattern matching
match getLegStatus trade with
| LegIsSettled -> // ...
| LegIsUnSettled -> // ...
// But you can still use higher-order functions too
trades |> List.exist (fun t -> getLegStatus t = LegIsSettled)
// Which can be rewritten (if you like point-free style):
trades |> List.exist (getLegStatus >> ((=) LegIsSettled))
// Or you can write helper function (which is more readable):
let legStatusIs check trade = getLegStatus trade = check
trades |> List.exist (legStatusIs LegIsSettled)