Используя переменную в сопоставлении с образцом в Ocaml или F#

У меня есть функция формы

'a -> ('a * int) list -> int

let rec getValue identifier bindings = 
  match bindings with
  | (identifier, value)::tail -> value
  | (_, _)::tail -> getValue identifier tail
  | [] -> -1

Я могу сказать это identifier не связывается путем, я хотел бы его к и действую как новая переменная в рамках выражения соответствия. Как я добираюсь identifier быть, что передается в функцию?

Хорошо! Я зафиксировал его с защитой шаблона, т.е. | (i, value)::tail when i = indentifier -> value но я нахожу это ужасным по сравнению со способом, которым я первоначально хотел сделать это (я только использую эти языки, потому что они довольно...). Какие-либо мысли?

9
задан Gilles 'SO- stop being evil' 14 November 2011 в 00:19
поделиться

4 ответа

Вы можете использовать активные шаблоны F # для создания шаблона, который будет делать именно то, что вам нужно. F # поддерживает параметризованные активные шаблоны, которые принимают совпадающее значение, но также принимают дополнительный параметр.

Вот довольно глупый пример, который терпит неудачу, когда значение равно нулю, и в противном случае завершается успешно и возвращает сложение значения и указанного параметра:

let (|Test|_|) arg value = 
  if value = 0 then None else Some(value + arg)

Вы можете указать параметр в сопоставлении с образцом следующим образом :

match 1 with
| Test 100 res -> res // 'res' will be 101

Теперь мы можем легко определить активный шаблон, который будет сравнивать совпадающее значение с входным аргументом активного шаблона. Активный шаблон возвращает параметр единицы , что означает, что он не связывает какое-либо новое значение (в приведенном выше примере он вернул некоторое значение, которое мы присвоили символу res ):

let (|Equals|_|) arg x = 
  if (arg = x) then Some() else None

let foo x y = 
  match x with
  | Equals y -> "equal"
  | _ -> "not equal"

Вы можете использовать это как вложенный шаблон, поэтому вы сможете переписать свой пример, используя активный шаблон Equals .

11
ответ дан 4 December 2019 в 07:47
поделиться

Это не прямой ответ на вопрос: как сопоставить значение переменной с образцом. Но это тоже не совсем не связано.

Если вы хотите увидеть, насколько мощным может быть сопоставление с образцом в ML-подобном языке, подобном F # или OCaml, взгляните на Moca .

Вы также можете взглянуть на код, сгенерированный Moca :) (не то чтобы что-то не так с компилятором, который много чего делает за вас. чтобы чувствовать, что они знают, во что обойдутся операции, которые они пишут).

5
ответ дан 4 December 2019 в 07:47
поделиться

Одна из прелестей функциональных языков - функции высшего порядка. Используя эти функции, мы убираем рекурсию и просто сосредотачиваемся на том, что вы действительно хотите делать. Чтобы получить значение первого кортежа, который соответствует вашему идентификатору, в противном случае верните -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

Эта статья Грэма Хаттона - отличное введение в то, что вы можете делать с функциями более высокого порядка.

7
ответ дан 4 December 2019 в 07:47
поделиться

Это распространенная жалоба, но я не думаю, что есть хороший обходной путь в целом; защита шаблона обычно является лучшим компромиссом. Однако в некоторых конкретных случаях есть альтернативы, например, пометить литералы атрибутом [] в F#, чтобы их можно было сопоставить.

3
ответ дан 4 December 2019 в 07:47
поделиться
Другие вопросы по тегам:

Похожие вопросы: