我通过使用活动模式编写递归下降解析器来学习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"
我的主要困惑似乎是关于&#39; |&#39;运营商。有时它似乎是模式类型的一部分,有时也是名称的一部分。
答案 0 :(得分:10)
您实际上并不需要实现自己的模式链接,因为您可以直接嵌套模式,从而为您提供所需的结果:
match 20 with
| IfBiggerThan10ThenDouble(IfLessThan100ThenDouble value) -> printfn "%A" value
| _ -> printfn "Did not match"
这将首先调用计算IfBiggerThan10ThenDouble
的{{1}}模式,并将值传递给嵌套模式20*2
。这再次使值加倍并将其绑定到IfLessThan100ThenDouble
符号(成功时)。
也就是说,value
模式的实现确实有效,可以像这样调用:
Chain
通常,活动模式match 20 with
| Chain (|IfBiggerThan10ThenDouble|_|) (|IfLessThan100ThenDouble|_|) value ->
printfn "%A" value // Should print 80
| _ -> printfn "Did not match"
实际上只是一个具有特殊名称的函数。您可以将其视为普通函数并通过编写(|P|_|)
来调用它,或者您可以将其视为值并将其作为参数传递给其他函数或参数化活动模式。如果您将(|P|_|) argument
实现为采用普通函数的模式,那么您的代码将起作用:
Chain
然后let (|Chain|_|) f g data =
f data |> Option.bind (fun r -> g data)
只是调用参数化的活动模式,并将两个函数作为参数。调用时,它会将结果绑定到模式Chain <arg1> <arg2> <pat>
。在上面的例子中,两个参数是表示模式的函数值(由于语法限制,这些函数值可能是普通函数,但不是lambda函数)。