Выполнение вычислений для типов опций F#

Я пытаюсь написать некоторую функцию, которая обрабатывает ошибки, возвращая двойные параметры вместо двойных. Многие из этих функций вызывают друг друга и поэтому принимают двойные опции в качестве входных данных для вывода других двойных опций. Проблема в том, что я не могу делать с двойными опциями то, что я могу делать с двойными - что-то простое, например, добавлять их с помощью «+».

Например, функция, которая делит два числа типа double и возвращает параметр типа double без ошибки деления на ноль. Затем другая функция вызывает первую функцию и добавляет к ней еще одну двойную опцию.

Скажите, пожалуйста, есть ли способ сделать это, или я совершенно неправильно понял значение типов опций F#.


person user3685285    schedule 23.04.2015    source источник
comment
попробуйте добавить несколько примеров кода, иллюстрирующих, что вы хотите реализовать и какие ошибки вы получаете   -  person Petr    schedule 23.04.2015
comment
Что-то настолько невинное, как Some(1.0) + Some(1.0), не работает. Если это действительно не работает, то я не могу его использовать, потому что у меня есть много функций, которые принимают двойные опции и возвращают двойные опции, и все они зависят друг от друга, чтобы выполнить некоторые математические операции.   -  person user3685285    schedule 23.04.2015
comment
То, что вы ищете, это вариант рабочего процесса. Взгляните на эту тему.   -  person scrwtp    schedule 23.04.2015
comment
...или просто используйте Option.bind.   -  person scrwtp    schedule 23.04.2015
comment
Возможно, это может помочь: fsharpforfunandprofit.com/posts/computation-expressions-bind   -  person Petr    schedule 23.04.2015


Ответы (4)


Это называется подъемом — вы можете написать функцию для подъема другой функции по двум параметрам:

let liftOpt f o1 o2 = 
        match (o1, o2) with
        | (Some(v1), Some(v2)) -> Some(f v1 v2)
        | _ -> None

то вы можете указать функцию для применения, например:

let inline addOpt o1 o2 = liftOpt (+) o1 o2
person Lee    schedule 23.04.2015
comment
На самом деле вы можете сделать еще один шаг вперед, чтобы сделать код более читаемым: определите liftOpt, как это сделано здесь, а затем (сделайте это очень-очень локально) затените + чем-то вроде let (+) o1 o2 = liftOpt(+) o1 o2. И теперь вы можете написать let x, y = Some 3.0, Some 2.0, а затем x + y. - person Daniel Fabian; 23.04.2015
comment
@DanielFabian Хороший совет, отличное место (ИМО) для этого было бы поместить поднятое (+) в module Option, чтобы расширить значение по умолчанию Option. Тогда только после open Option у вас будет поднятый (+) в области видимости :) - person Patryk Ćwiek; 24.04.2015

liftA2, как упоминалось выше, обеспечит общий способ «поднять» любую функцию, которая работает с double аргументами, до функции, которая может работать с double option аргументами.

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

let (<+>) a b =
    match (a, b) with
    | (Some x, Some y) -> Some (x + y)
    | (Some x, None)   -> Some (x)
    | (None, Some x)   -> Some (x)
    | (None, None)     -> None

Обратите внимание, что liftA2 не будет автоматически помещать случаи, когда вы хотите добавить None к Some(x).

Метод liftA2 для разделения также нуждается в специальной обработке, но его структура, как правило, такая, какую мы написали бы сами.

let (</>) a b =
    match (a, b) with
    | (Some x, Some y) when y <> 0.0d -> Some (x/y)
    | _ -> None

Вы можете использовать эти функции, например

Some(2.0) <+> Some(3.0) // will give Some(5.0)
Some(1.0) </> Some(0.0) // will give None

Кроме того, строго говоря, lift определяется как "функция более высокого порядка" - то, что принимает функцию и возвращает другую функцию.

Таким образом, это будет выглядеть примерно так:

let liftOpt2 f =
    (function a b ->
        match (a, b) with
        | (Some (a), Some (b)) -> f a b |> Some
        | _ -> None)
person John Azariah    schedule 24.04.2015

В конце концов я понял, что на самом деле мне нужна была функция Option.get, которая просто берет вариант «а» и возвращает «а». Таким образом, я могу сопоставлять шаблоны и возвращать нужные мне значения.

person user3685285    schedule 24.04.2015

В этом случае вы можете рассмотреть Nullables вместо Options по двум причинам:

  • Nullables — это типы значений, а Options — ссылочные типы. Если у вас есть большие коллекции этих двойников, использование Nullables сохранит числа в стеке, а не в куче, что потенциально улучшит вашу производительность.
  • Microsoft предоставляет набор встроенных операторов, допускающих значение NULL, которые позволяют вам напрямую выполнять математические операции с нулевыми значениями, точно так же, как вы пытаетесь сделать с параметрами.
person Joel Mueller    schedule 28.04.2015