在Ocaml或F#中使用模式匹配中的变量

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活动模式重写示例.


Ces*_*oza 7

功能语言的优点之一是高阶函数.使用这些函数,我们将递归输出,并专注于您真正想要做的事情.这是获取与您的标识符匹配的第一个元组的值,否则返回-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的这篇论文很好地介绍了你可以用更高阶函数做些什么.

  • *眼睛爆炸*无点样式很聪明,但不可读且无法维护。`fun x -> x |> List.map fst |> List.filter (fun y -> y = identifier)` 在不牺牲可读性的情况下表达了同样的事情。 (2认同)

Pas*_*uoq 5

这不是问题的直接答案:如何模式匹配变量的值.但它也不完全无关.

如果你想看看类似于F#或OCaml的类似ML的语言模式匹配有多强大,请看看Moca.

你也可以看看Moca生成的代码:)(并不是说编译器在你背后为你做了很多事情都有什么问题.在某些情况下,它甚至是可取的,但很多程序员都喜欢感觉到它们知道他们正在写的操作会花费多少钱.