我正在通过使用活动模式编写递归下降解析器来学习F#.
由于我的所有规则或部分活动模式都需要以不同的方式组合它们,但我对将活动模式作为参数传递的语法感到非常沮丧.
以下示例显示了我遇到的问题:
// Combines two patterns by chaining them.
let (|Chain|_|) (|Pattern1|_|) (* Should I use pipes here? *) (|Pattern2|_|) data =
match data with
|Pattern1 result ->
match result with
|Pattern2 result2 -> Some result2
|_ -> None
|_ -> None
// Stupid test patterns
let (|IfBiggerThan10ThenDouble|_|) value = if value > 10 then Some (value*2) else None
let (|IfLessThan100ThenDouble|_ |) value = if value < 100 then Some (value*2) else None
match 20 with
// Do I need pipes here?
|Chain (IfBiggerThan10ThenDouble IfLessThan100ThenDouble) value -> printfn "%A" value // Should print 80
| _ -> printfn "Did not match"
Run Code Online (Sandbox Code Playgroud)
我的主要困惑似乎是关于'|' 运营商.有时它似乎是模式类型的一部分,有时也是名称的一部分.
Tom*_*cek 11
您实际上并不需要实现自己的模式链接,因为您可以直接嵌套模式,从而为您提供所需的结果:
match 20 with
| IfBiggerThan10ThenDouble(IfLessThan100ThenDouble value) -> printfn "%A" value
| _ -> printfn "Did not match"
Run Code Online (Sandbox Code Playgroud)
这将首先调用IfBiggerThan10ThenDouble计算模式20*2并将值传递给嵌套模式IfLessThan100ThenDouble.这再次使值加倍并将其绑定到value符号(成功时).
也就是说,你的Chain模式实现确实有效,可以这样调用:
match 20 with
| Chain (|IfBiggerThan10ThenDouble|_|) (|IfLessThan100ThenDouble|_|) value ->
printfn "%A" value // Should print 80
| _ -> printfn "Did not match"
Run Code Online (Sandbox Code Playgroud)
通常,活动模式(|P|_|)实际上只是一个具有特殊名称的函数.您可以将其视为普通函数并通过写入来调用它,(|P|_|) argument或者您可以将其视为值并将其作为参数传递给其他函数或参数化活动模式.如果您实现Chain为采用普通函数的模式,您的代码将起作用:
let (|Chain|_|) f g data =
f data |> Option.bind (fun r -> g data)
Run Code Online (Sandbox Code Playgroud)
然后Chain <arg1> <arg2> <pat>只是用两个函数作为参数调用参数化的活动模式.调用时,它会将结果绑定到模式<pat>.在上面的例子中,两个参数是表示模式的函数值(这些函数值可能是普通函数,但由于语法限制,因此不是lambda函数).