Боюсь, что в компиляторе F # нет обработки логических операторов, которые позволили бы вам их переопределить (как в C #).Насколько я могу судить, x && y
компилируется просто как if x then y else false
, поэтому x
должно быть логическим.Я не проверял, поддерживает ли компилятор F # это поведение для типов, объявленных в C #, но я не думаю, что это так.
Насколько я знаю, лучший способ эмулировать короткое замыкание behvaior для вашегособственный оператор должен использовать ключевое слово lazy
для создания отложенных значений.Затем вы можете написать что-то вроде:
let foo b =
printfn "foo %b" b
MyBool(b)
lazy foo true &&! lazy foo false // Calls 'foo' for both branches
lazy foo false &&! lazy foo false // Calls 'foo' only for the first one
Эти два оператора могут быть определены с использованием статических ограничений членов, поэтому они должны (в принципе) работать для любых типов, которые реализуют операторы, требуемые C #.
let inline (&&!) (x:Lazy<_>) (y:Lazy<_>) =
if (^T: (static member op_False : ^T -> bool) x.Value)
then x.Value else x.Value &&& y.Value
let inline (||!) (x:Lazy<_>) (y:Lazy<_>) =
if (^T: (static member op_False : ^T -> bool) x.Value)
then x.Value else x.Value ||| y.Value
Затем вы можете определить свои типы MyBool
со всеми необходимыми операторами (в качестве примечания: он должен использоваться естественным образом из C #, если вы определите его следующим образом):
type MyBool(b) =
member x.Value = b
static member (|||) (v1: MyBool, v2 : MyBool) =
MyBool(v1.Value || v2.Value)
static member (&&&) (v1: MyBool, v2 : MyBool) =
MyBool(v1.Value && v2.Value)
static member op_True (v: MyBool) = v.Value
static member op_False (v: MyBool) = not v.Value