Не удалось расширить операторы в F #? - PullRequest
3 голосов
/ 29 ноября 2011
module FSharp=
let Point2d (x,y)= Point2d(x,y)
let Point3d (x,y,z)= Point3d(x,y,z)
type NXOpen.Point3d with
    static member ( * ) (p:Point3d,t:float)= Point3d(p.X*t,p.Y*t,p.Z*t)
    static member ( * ) (t:float,p:Point3d)= Point3d(p.X*t,p.Y*t,p.Z*t)
    static member (+) (p:Point3d,t:float)= Point3d(p.X+t,p.Y+t,p.Z+t)
    static member (+) (t:float,p:Point3d)= Point3d(p.X+t,p.Y+t,p.Z+t)
    static member (+) (p:Point3d,t:Point3d)= Point3d(p.X+t.X,p.Y+t.Y,p.Z+t.Z)

let a=Point3d (1.,2.,3.)
let b=1.0
let c=a * b//error

Ошибка 15: тип 'float' не соответствует типу
'Point3d' E: \ Work \ extension-RW \ VS \ extension \ NXOpen.Extension.FSharp \ Module1.fs 18 13 NXOpen.Extension.FSharp

Я хочу расширить методы Point3d, некоторые новые операторы. Но это не проходит.

Ответы [ 2 ]

5 голосов
/ 29 ноября 2011

Если тип Point3d объявлен в отдельной сборке, которую вы не можете изменить, то (к сожалению) нет способа реализовать новые перегрузки стандартных операторов, таких как + или *.Код в вашем вопросе добавляет операторы в качестве методов расширения, но компилятор F # не ищет методы расширения при поиске перегруженных операторов.

Если вы не можете изменить библиотеку, есть три вещи, которые вы можетеdo:

  • Создайте оболочку для Point3d, которая хранит значение Point3d и реализует все операторы
    (но это, вероятно, будет довольно неэффективно)

  • Определите новые операторы, которые не конфликтуют со встроенными.Например, вы можете использовать +$ и $+ для умножения на скаляр слева и справа.Чтобы объявить такой оператор, вы должны написать:

    let (+$) (f:float) (a:Point3d) = (...)
    
  • Реализуйте свой собственный тип Point3d, который выполняет всю работу, возможно, с функцией преобразования, которая превращает его в Point3d, когдавам нужно вызвать библиотеку.

Трудно сказать, какой вариант является лучшим - второй подход, вероятно, самый эффективный, но он сделает код несколько уродливее.В зависимости от вашего сценария вариант 1 или 3 может также работать.

3 голосов
/ 30 ноября 2011

Действительно, это возможно.Существует способ расширить двоичные операторы, используя один-единственный и малоизвестный троичный оператор ?<-.Так что в вашем случае вы можете попробовать это:

type SumPoint3d = SumPoint3d with
    static member        (?<-) (p:Point3d, SumPoint3d, t        ) = Point3d(p.X + t  , p.Y + t  , p.Z + t  )
    static member        (?<-) (t        , SumPoint3d, p:Point3d) = Point3d(p.X + t  , p.Y + t  , p.Z + t  )
    static member        (?<-) (p:Point3d, SumPoint3d, t:Point3d) = Point3d(p.X + t.X, p.Y + t.Y, p.Z + t.Z)
    static member inline (?<-) (a        , SumPoint3d, b        ) = a + b

type ProdPoint3d = ProdPoint3d with    
    static member        (?<-) (p:Point3d, ProdPoint3d, t        ) = Point3d(p.X * t, p.Y * t, p.Z * t)
    static member        (?<-) (t        , ProdPoint3d, p:Point3d) = Point3d(p.X * t, p.Y * t, p.Z * t)
    static member inline (?<-) (a        , ProdPoint3d, b        ) = a * b

let inline ( + ) a b =  a ? (SumPoint3d ) <- b
let inline ( * ) a b =  a ? (ProdPoint3d) <- b

let a=Point3d (1.,2.,3.) 
let b=1.0

Теперь вы можете попробовать:

> let c=a * b ;;
val c : Point3d = Point3d (1.0,2.0,3.0)

>  2 * 3 ;;
val it : int = 6
...