我不确定是否允许非静态公共成员活动模式,但您可以在没有编译器抱怨的情况下定义它们.如果允许它们与一个匹配的语法是什么?编译器在FooBar2.doSomething中为Foo提供了类型不匹配.期待一个'a -> Choice<'b,'c>给定的'a -> 'd -> Choice<unit,unit>
// No error in this class, static works great
type FooBar() =
static member (|Foo|Bar|) (x, y) =
match x = y with
| true -> Foo
| false -> Bar
member x.doSomething y =
match x, y with
| Foo -> ()
| Bar -> ()
type FooBar2() =
member x.(|Foo|Bar|) y =
match x = y with
| true -> Foo
| false -> Bar
// compiler error …Run Code Online (Sandbox Code Playgroud) 我有类型的记录
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 ;
}
Run Code Online (Sandbox Code Playgroud)
贸易腿显然是一种交易类型.一条腿可能已经结算或未结算(或未结算但已确认价格) - 因此我已定义了活动模式:
let (|LegIsSettled|LegIsConfirmed|LegIsUnsettled|) (l: tradeLeg) =
if …Run Code Online (Sandbox Code Playgroud) 我正在尝试了解Active Patterns,所以我正在玩FizzBuzz:
let (|Fizz|_|) i = if i % 3 = 0 then Some Fizz else None
let (|Buzz|_|) i = if i % 5 = 0 then Some Buzz else None
let (|FizzBuzz|_|) i = if i % 5 = 0 && i % 3 = 0 then Some FizzBuzz else None
let findMatch = function
| Some Fizz -> "Fizz"
| Some Buzz -> "Buzz"
| Some FizzBuzz -> "FizzBuzz"
| _ -> ""
let fizzBuzz = seq …Run Code Online (Sandbox Code Playgroud) 当涉及到F#的许多领域时,我仍然是新手.我出于好奇而不是出于实际的业务需求而提出这个问题.有没有办法匹配列表中的前n个项目,无论它们出现的顺序如何?为了澄清,请考虑以下示例:
type MyEnum =
| Foo of int
| Bar of float
| Baz of string
let list = [ Foo 1 ; Bar 1.0 ; Baz "1" ]
Run Code Online (Sandbox Code Playgroud)
现在,假设我想调用some_func列表中的前两个项是a Foo和a Bar,以任何顺序.只匹配两种可能的排列很容易:
let result =
match list with
| Foo n :: Bar x :: _
| Bar x :: Foo n :: _ -> some_func n x
| _ -> failwith "First 2 items must be Foo and Bar"
Run Code Online (Sandbox Code Playgroud)
但是,如果我需要调用一个函数,如果前3项是a Foo,Bar …
由于我只发现了关于这个错误的日文页面,我想,让我们记录它并在这里问,因为我的日语有点生疏.
如果我有以下FSharp活动模式(简化示例):
let (|InRange|OutOfRange|) from too =
function
| input when input >= from && input <= too -> InRange
| _ -> OutOfRange
Run Code Online (Sandbox Code Playgroud)
它完美编译并显示其类型:
val ( |InRange|OutOfRange| ) :
from:'a -> too:'a -> _arg1:'a -> Choice<unit,unit> when 'a : comparison
Run Code Online (Sandbox Code Playgroud)
但是当我尝试使用它时,即如下所示,它会抛出一个错误:
let test i = match i with
| InRange 10 20 -> "in range"
| _ -> "out of range"
Run Code Online (Sandbox Code Playgroud)
抛出:错误FS0722:只有返回一个结果的活动模式可以接受参数
我可以通过把它变成两个单例参数化的活动模式来解决它,每个都返回None/Some(x),但我仍然想知道为什么我不被允许这样做和/或是否有我可以使用的语法我是不知道.我也想知道它为什么编译,但我不能用它?
有没有办法使用以下形式的区别联合与活动模式匹配?我找不到任何例子.
这就是我想要做的:
type c = a | b
type foo =
| bar1
| bar2 of c
//allowed
let (|MatchFoo1|_|) aString =
match aString with
| "abcd" -> Some bar1
| _ -> None
//not allowed
let (|MatchFoo2|_|) aString =
match aString with
| "abcd" -> Some (bar2 of a)
| _ -> None
Run Code Online (Sandbox Code Playgroud)
为什么"Some"不能以第二种方式使用?还有另一种方法可以达到同样的目的吗?
我注意到我无法使用相同的选项创建两个活动模式,但我可以有两个类似的模式没有任何警告:
let (|A|B|C|) c =
if (c = 'a') then A
else if (c = 'b') then B
else C
let (|A|B|D|) c =
if (c = '1') then A
else if (c = '2') then B
else D
Run Code Online (Sandbox Code Playgroud)
所以当这种方式匹配时:
let check myvar =
match myvar with
| A -> printf "match A\n"
| n -> printf "match other %A\n" n
Run Code Online (Sandbox Code Playgroud)
有时候是这样的:
check 'x' // match other 'x'
check 'a' // match other 'a' !!
check '1' // match A …Run Code Online (Sandbox Code Playgroud) 我正在使用活动模式来解析csv格式的使用日志中的使用事件.下面列出了活动模式部分.解析整个文件效果很好,生成的序列充满了各种UsageEvents.
type SystemName = string
type SystemVersion = string
type MAC = string
type Category = string
type Game = string
type Setting = string
type StartupLocation = string
type UsageEvent =
| SystemStart of DateTime * SystemVersion * SystemName * MAC
| SystemEnd of DateTime
| GameStart of DateTime * Category * Game * Setting * StartupLocation
| GameEnd of DateTime * Category * Game
| Other
let (|SystemStart|SystemEnd|GameStart|GameEnd|Other|) (input : string list) =
match List.nth input 0 with …Run Code Online (Sandbox Code Playgroud) 让我们为具有几种类型的二进制节点的树的类型定义,以及其他类型的节点,即
type Tree =
| BinaryNodeA of Tree * Tree
| BinaryNodeB of Tree * Tree
| [Other stuff...]
Run Code Online (Sandbox Code Playgroud)
我想使用递归函数来操纵这个树,该递归函数可以例如交换任何类型的二进制节点的子节点(通过构造新节点).让我疯狂的问题:如何匹配所有BinaryNodes,以便Node风格成为"参数",以便具有可应用于任何BinaryNode风格的通用交换,以返回该风味的交换节点?
我知道如何使用活动模式匹配所有BinaryNodes树:
let (|BinaryNode|_|) (tree : Tree) =
match tree with
| BinaryNodeA _ | BinaryNodeB _ -> Some(tree)
| _ -> None
Run Code Online (Sandbox Code Playgroud)
但这还不够好,因为以下似乎无法实现:
match tree with
| [cases related to unary nodes..]
| BinaryNode a b -> BinaryNode b a
Run Code Online (Sandbox Code Playgroud)
换句话说,我还没有找到使用BinaryNode风格的方法,就像它是a和b之类的参数一样.相反,似乎我必须分别匹配每个BinaryNode风格.如果存在大量二进制节点风格,这可能具有实际意义.对于Fsyacc/Fslex生成的解析器/词法分析器,类型树是AST,它限制了重构它的选项.有任何想法吗?
我在F# Design PatternsGene Belitski 的优秀书中找到了这段代码:
let (| `` I'm active pattern `` |) x = x + 2
let (`` I'm active pattern `` y) = 40
(*
val ( |`` I'm active pattern ``| ) : x:int -> int
val y : int = 42
*)
Run Code Online (Sandbox Code Playgroud)
作者认识到这是
"如果你记得一个值的let绑定是基于模式匹配的数据反汇编的角落情况,那么一个稍微令人难以置信的例子变得清晰,因此I'm active pattern应用于输入参数40并将结果42绑定到x."
我不明白.为什么I'm active pattern40适用于40,因为40在右侧?我直觉地猜测y = 38,而不是42,将表达式let (`` I'm active pattern `` y) = 40视为隐式函数.
谁能解释一下?