San*_*eek 9 variables binding f# ocaml pattern-matching
我有一个表格的功能
'a -> ('a * int) list -> int
let rec getValue identifier bindings =
match bindings with
| (identifier, value)::tail -> value
| (_, _)::tail -> getValue identifier tail
| [] -> -1
Run Code Online (Sandbox Code Playgroud)
我可以identifier
说它不受我想要的约束,并且在匹配表达式中充当新变量.如何identifier
成为传递给函数的内容?
好!我用模式防护装置固定了它,| (i, value)::tail when i = indentifier -> value
但是我觉得这比我最初想要做的那样丑陋(我只使用这些语言,因为它们很漂亮......).有什么想法吗?
Tom*_*cek 11
您可以使用F#活动模式创建一个完全符合您需要的模式.F#支持参数化的活动模式,它采用您匹配的值,但也需要一个额外的参数.
这是一个非常愚蠢的例子,当value
它为零时失败,否则成功并返回值和指定参数的添加:
let (|Test|_|) arg value =
if value = 0 then None else Some(value + arg)
Run Code Online (Sandbox Code Playgroud)
您可以在模式匹配中指定参数,如下所示:
match 1 with
| Test 100 res -> res // 'res' will be 101
Run Code Online (Sandbox Code Playgroud)
现在,我们可以轻松定义一个活动模式,将匹配的值与活动模式的输入参数进行比较.活动模式返回unit option
,这意味着它不绑定任何新值(在上面的示例中,它返回了我们分配给符号的一些值res
):
let (|Equals|_|) arg x =
if (arg = x) then Some() else None
let foo x y =
match x with
| Equals y -> "equal"
| _ -> "not equal"
Run Code Online (Sandbox Code Playgroud)
您可以将其用作嵌套模式,因此您应该能够使用Equals
活动模式重写示例.
功能语言的优点之一是高阶函数.使用这些函数,我们将递归输出,并专注于您真正想要做的事情.这是获取与您的标识符匹配的第一个元组的值,否则返回-1:
let getValue identifier list =
match List.tryFind (fun (x,y) -> x = identifier) list with
| None -> -1
| Some(x,y) -> y
//val getValue : 'a -> (('a * int) list -> int) when 'a : equality
Run Code Online (Sandbox Code Playgroud)
Graham Hutton的这篇论文很好地介绍了你可以用更高阶函数做些什么.