[英]F# Active Pattern List.filter or equivalent
我有类型的记录
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
然后确定交易是否已经结算(基于匹配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。
问题有两个:
有没有办法抽象功能/表达
(fun l -> match l with | LegIsSettled -> false | _ -> true)
这样
let itemMatchesPattern pattern item =
match item with
| pattern -> true
| _ -> false
我可以写(因为我正在重用这个设计模式):
let curriedItemMatchesPattern = itemMatchesPattern LegIsSettled
if List.exists curriedItemMatchesPattern t.tradeLegs then TradeIsSettled
else TradeIsUnsettled
思考?
要回答有关活动模式的问题,让我使用一个更简单的示例:
let (|Odd|Even|) n =
if n % 2 = 0 then Even else Odd
当您使用(|Odd|Even|)
声明具有多个选项的模式时,编译器会将其理解为返回Choice<unit, unit>
类型的值的函数。 因此,您可以使用的活动模式是整个组合|Odd|Even|
而不只是两个你可以独立使用的结构(例如|Odd|
和|Even|
)。
可以将活动模式视为第一类函数,但如果您使用具有多个选项的模式,则无法对其执行任何操作:
let pattern =(| Odd | Even |);; val模式:int - >选择
您可以编写测试值是否与指定模式匹配的函数,但是您需要很多函数(因为有很多类型参数重载的Choice
类型):
let is1Of2 pattern item =
match pattern item with
| Choice1Of2 _ -> true
| _ -> false
> is1Of2 (|Odd|Even|) 1
val it : true
像你这样的东西可以用在你的情况下,但它远非完美。
如果你声明多个部分活动模式,你可以做得更好一些(但是你当然会松开完整活动模式的一些好方面,比如完整性检查):
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)
除了Tomas关于活动模式的实际细节的要点之外,请注意你总是可以缩短fun x -> match x with |...
到function | ...
function | ...
,这将节省一些键击以及构成可能无意义的标识符的需要。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.