как явно ссылаться на оператора - PullRequest
2 голосов
/ 09 июля 2020

Я пытаюсь иметь go с Microsoft.ML.Probabilisti c, а примеры находятся в C#.

например

static void Main(string[] args)
{
    var firstHeads = Variable.Bernoulli(0.5);
    var secondHeads = Variable.Bernoulli(0.5);
    var bothHeads = firstHeads & secondHeads;
}

теперь есть там происходит немного магии c, оператор & разрешается компилятором C# как

Variable<bool>.operator &(Variable<bool> a, Variable<bool> b)

(на самом деле я, хотя я использую C# более 15 лет , Я на самом деле не знаю, как явно ссылаться на этот оператор, я просто позволяю компилятору выполнять тяжелую работу ... но это в стороне)

Я хочу сделать это в F #, поэтому я пишу

let main argv =
    let firstCoinHeads = Variable.Bernoulli 0.5
    let secondCoinHeads = Variable.Bernoulli 0.5
    let bothHeads = firstCoinHeads & secondCoinHeads
    0 

но это не компилируется, потому что компилятор F # «ожидалось, что это выражение будет логическим» для подвыражений «firstCoinHeads» и «secondCoinHeads».

это вроде как раздражает ... . Итак, как мне явно заставить F # использовать правильный оператор?

Ответы [ 2 ]

4 голосов
/ 09 июля 2020

In. NET (и в F #, в большей степени) операторы компилируются в методы с именем op_Xyz, где Xyz описывает сам оператор (для . NET перегружаемых операторов ) или символы, включенные в оператор (для более богатых операторов F #).

В частности, оператор & компилируется в op_BitwiseAnd, и вот как вы можете получить к нему доступ:

let bothHeads = Variable.op_BitwiseAnd(firstCoinHeads, secondCoinHeads)

Исходная проблема, с которой вы столкнулись, связана с тем, что в F # оператор & является «специальным» (предполагается, что для обратной совместимости с Ocaml). Компилятор специально обрабатывает это, заставляя аргументы быть bool и выдает предупреждение, если вы пытаетесь его переопределить. Это немного раздражает, да, но вот и мы.

Но вы можете определить себе другой оператор как расширение для типа Variable:

type Variable<'t> with
    static member (&.)(a, b) = Variable<bool>.op_BitwiseAnd(a, b)

А затем используйте это так:

let bothHeads = firstCoinHeads &. secondCoinHeads
1 голос
/ 11 июля 2020

Данный ответ @Fyodor Soikin не является неправильным, но предлагаемое решение не является необходимым. Кажется, есть небольшая путаница с операторами:

  • Побитовое and действительно компилируется как op_BitwiseAnd
  • In C#, побитовое и равно & .
  • В F # побитовое и равно &&&. Это тот, который вам нужен.
  • В F # & используется в выражениях соответствия, означающих «и», и как унарный оператор address-of. Для этого оператора нет сопоставления по умолчанию. (в случае переопределения он становится op_Amp).
  • Логическое "и" в F # равно &&.

Конечно, вы можете переопределить &&& в F #. Не столько переопределение оператора адресации (вы получите предупреждение).

Однако, если тип перегружает оператор, F # просто выберет этот оператор, если вы используете соответствующий синтаксис оператора c. В этом случае &&&. Да, это действительно сбивает с толку.

Если я установлю Microsoft.ML.Probabilistic и Microsoft.ML.Probabilistic.Compilers, я могу сделать следующее (синтаксис nuget доступен с --langversion:preview):

> #r "nuget: Microsoft.ML.Probabilistic";;
> open Microsoft.ML.Probabilistic;;
[Loading C:\Users\Me\AppData\Local\Temp\nuget\10644\Project.fsproj.fsx]
namespace FSI_0138.Project

> #r "nuget: Microsoft.ML.Probabilistic.Compiler";;
> open Microsoft.ML.Probabilistic.Models;;
[Loading C:\Users\Me\AppData\Local\Temp\nuget\10644\Project.fsproj.fsx]
namespace FSI_0143.Project

>let firstCoinHeads = Variable.Bernoulli 0.5
let secondCoinHeads = Variable.Bernoulli 0.5;;
Binding session to 'C:\Users\Abel\.nuget\packages\microsoft.ml.probabilistic\0.3.1912.403\lib\netstandard2.0\Microsoft.ML.Probabilistic.dll'...
val firstCoinHeads : Variable<bool> = vbool0
val secondCoinHeads : Variable<bool> = vbool1

> let bothHeads = firstCoinHeads &&& secondCoinHeads;;
val bothHeads : Variable<bool> = vbool2

Как видите, здесь нет необходимости создавать «свой собственный» специальный оператор, просто используйте фактический оператор «побитового и»: &&&.

Если вы снова столкнетесь с этим, появится список какой оператор соответствует какому методу: https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/operator-overloading. Примечательно:

введите описание изображения здесь

...