Извлечь необработанную переменную из опции - PullRequest
0 голосов
/ 09 февраля 2019

Я работаю с простой функцией, которая должна извлекать значение 'a из объекта типа 'a option.Я видел здесь примеры, которые выглядят так, как я написал, но OCaml путает это с функцией, которая принимает 'a option option, и я не уверен почему.

let extract_x x = match x with
  | Some state -> state
  | None -> None

Интерпретация OCaml, как видно из utop:val extract_x : 'a option option -> 'a option = <fun>

Ответы [ 2 ]

0 голосов
/ 10 февраля 2019

Давайте представим, что мы (или, скорее, и ) ocaml typechecker, и мы хотим определить тип вашего значения extract_x

let extract_x x = ...

Хорошо, так что мы знаем, чтотип extract_x должен быть функцией, _ -> _.Давайте назовем неизвестный на данный момент тип ввода a и тип вывода z, тогда переменная x имеет тип a:

extract_x : a -> z
x : a
... : z

Давайте посмотрим глубже:

let extract_x x = match x with
  | p1 -> v1
  | p2 -> v2

Здесь я назвал шаблоны и значения, чтобы не записывать их.Теперь мы знаем, что p1 и p2 должны соответствовать значениям типа a и что v1 и v2 имеют тип z.Давайте рассмотрим паттерны:

| Some state -> ...
| None -> ...

Итак, теперь мы можем сделать вывод, что a должно быть чем-то вроде option.Допустим, это b option.Теперь у нас есть:

extract_x : b option -> z
x : b option
... : z
(In first case only):
  state : b

Давайте рассмотрим первый случай:

  | Some state -> state

Итак, мы теперь выводим, что z = b, то есть тип, который должен быть возвращен из этой функции:тип state, который мы назвали b.Давайте рассмотрим другой случай:

  | None -> None

Ну, значение (то есть бит после ->) None является типом параметра.Давайте назовем это c option, и мы также знаем, что это должен быть тип z, поэтому давайте запишем, что у нас есть:

extract_x : a -> z
a = b option
z = b
z = c option

Итак, мы выводим, что b = c option так a = c option option такпометив переменные произвольного типа как полиморфные, мы получим:

extract_x : 'a option option -> 'a option

Это полезная функция (в общем случае называемая bind), но не та, которую вы хотите.Вот как вы можете написать функцию с типом 'a option -> 'a:

let extract_x x =
  match x with
  | Some x -> x
  | None -> failwith "extract_x: expected Some"

Однако вы, вероятно, вообще не хотите эту функцию, потому что если у вас есть опция, то это может быть None, чтовызовет активацию этой функции, и если у вас есть опция, которая всегда Some, тогда вы должны попытаться изменить ваши типы, чтобы выразить, что эта вещь не является дополнительной.В противном случае может показаться, что недопустимое значение None является допустимым, поскольку оно может быть построено.

Вот как на самом деле вы можете иметь дело с извлечением значений из опций более безопасным способом:

...
match t.x with
| None -> failwith "invariant for foo violated in bar”
| Some x -> (* carry on *)
  ...

(* don’t do this *)
type 'a one_or_two = 'a option * 'a option
...
  let (first, second) = ... : _ one_or_two in
  match first with
  | None ->
    (* now we know second must be Some *)
    let second = extract_x second in
    ...

(* do this instead *)
type 'a one_or_two = First of 'a | Second of 'a | Both of 'a * 'a
0 голосов
/ 09 февраля 2019

Аргумент x имеет тип 'option option, потому что extract_x возвращает либо None, либо значение состояния.Это означает, что «состояние» само должно быть вариантом варианта.Поэтому x, для которого вы используете сопоставление с шаблоном в качестве опции («Некоторое состояние»), должно быть параметром опции.

Чтобы решить эту проблему, в сопоставлении с шаблоном необходим регистр None для оценки чего-либо другого.чем опция, с тем же типом, что и «состояние».

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...