Перегруженные встроенные операторы в F#: ( |+|)

Я пытаюсь определить перегруженный оператор, например |+|, в дальнейшем:

let inline ( |+| ) (m1 : #IMeasurable) (m2 : #IMeasurable) = m1.Measure + m2.Measure

Проблема в том, что я не могу сделать что-то вроде:

let three = m1 |+| m2 |+| m3

Потому что оператор |+| не определено для случая (m1 : int) (m2 : #IMeasurable), Есть ли способ перегрузить этот оператор или использовать статические ограничения типа, чтобы сделать возможным приведенное выше выражение? Есть ли способ изменить IMeasurable (который я могу редактировать), чтобы это было возможно? Что-нибудь еще, что позволило бы вышеупомянутому выражению работать?

Спасибо.

2 ответа

Решение
type Overloads = Overloads with
    static member ($) (Overloads, m1: #IMeasurable) = fun (m2: #IMeasurable) -> m1.Measure + m2.Measure 
    static member ($) (Overloads, m1: int) = fun (m2: #IMeasurable) -> m1 + m2.Measure

let inline ( |+| ) m1 m2 = (Overloads $ m1) m2

Не проверено, так как у меня нет IMeasurable, но он может сделать работу.

Если вы определяете оператор, который ведет себя как + тогда я думаю, что лучший дизайн - это определить оператор, который возвращает значение того же типа, что и тип его аргументов. Это значит, что я бы сменил оператора на возврат IMeasurable вместо int:

type IMeasurable =
  abstract Measure : int

let newMeasure m = 
  { new IMeasurable with 
      member x.Measure = m }

let inline ( |+| ) (m1 : #IMeasurable) (m2 : #IMeasurable) = 
  newMeasure (m1.Measure + m2.Measure)

Это сделает определение оператора более единообразным и более простым в использовании. Код, который вы хотели написать, теперь будет работать (возвращая IMeasurable), но вы также можете использовать Seq.reduce:

// Now you can add multiple measure values without issues
let res = (newMeasure 2) |+| (newMeasure 3) |+| (newMeasure 4)

// Moreover, you can also use `Seq.reduce` which would not work
// with your original operator (because it has wrong type)
let res = [newMeasure 2; newMeasure 3; newMeasure 4] |> Seq.reduce (|+|)

Тем не менее, если вы действительно хотите перегрузить оператор, который определяется с помощью let и вы не можете добавить его к типу в качестве статического члена (потому что вы не можете изменить тип), тогда вам нужно будет использовать трюк, который описывает Густаво

Другие вопросы по тегам