Когда внедрять нулевой элемент в Computation Expression?

Почему я не могу использовать pattern matching function в вычислительных выражениях без реализации члена Zero?

Например, может ли кто-нибудь объяснить, почему он позволяет разрешать pattern matching expression, но не pattern matching function?

type MaybeBuilder() =
    member __.Bind (x, f) = match x with Some a -> f a | None -> None
    member __.Return x = Some x

let maybe = MaybeBuilder()

// Errors: FS0708 This control construct may only be used
// if the computation expression builder defines a 'Zero' method
maybe { Some 1 |> function Some x -> return x | None -> return 0 }
maybe { Some 1 |> fun x -> match x with Some x' -> return x' | None -> return 0 }

// Ok
maybe { match Some 1 with Some x -> return x | None -> return 0 }

person MiP    schedule 12.01.2018    source источник
comment
Пробовали ли вы реализовать метод Zero и посмотреть, что получится? Я ожидаю, что вы будете удивлены - проблема, скорее всего, не в том, что вы ожидаете.   -  person kvb    schedule 12.01.2018


Ответы (1)


Эта ошибка, по-видимому, является следствием тонкой проблемы с вашим примером. Когда вы пишете maybe { Some 1 |> function Some x -> return x | None -> return 0 }, это эквивалентно следующему коду

let expr1 = function Some x -> return x | None -> return 0
let expr2 = Some 1 |> expr1

maybe { expr2 }

что показывает, что

  1. вы не вызываете return для результата expr2, поэтому компилятор может только догадываться, что вы хотите, и запрашивает метод Zero(), чтобы дать значение результата maybe { expr2 }, и
  2. вызовы return, которые у вас есть, используются в неправильной области (и если вы разделите свой код таким образом, компилятор будет жаловаться), поэтому, даже если вы реализуете Zero(), он не скомпилируется.

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

maybe { return Some 1 |> function Some x -> x | None -> 0 }

или вы можете добавить выражение вычисления maybe внутри ветвей функции expr1. В этом примере это выглядит плохо, но может быть жизнеспособным для более сложной логики, которая не всегда может быть в контексте maybe { } builder.

Some 1 |> function Some x -> maybe { return x } | None -> maybe { return 0 }
person Honza Brestan    schedule 12.01.2018