Перегруженные встроенные операторы в 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
и вы не можете добавить его к типу в качестве статического члена (потому что вы не можете изменить тип), тогда вам нужно будет использовать трюк, который описывает Густаво