2011-11-29 111 views
3
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:類型 '浮動' 不匹配的類型
'三維點' E:\工作\擴展-RW \ VS \擴展\ NXOpen.Extension.FSharp \ Module1.fs 18 13 NXOpen .Extension.FSharp無法在F#中擴展運算符?

我想擴展Point3d方法,一些新的操作符。但它並沒有超過。

回答

3

確實有可能。 有一種方法可以使用唯一的和little known ternary operator ?<-來擴展二元運算符。所以你的情況,你可以試試這個:

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 
+0

等一下,這不會破壞常規的'*'運算符嗎? 'inline'-magic-ness允許具有相同名稱的多個函數,並且方法重載? – Alxandr

+0

@Alxandr是的,三元運算符被重載,'''''運算符被重定向到三元,所以它也會被重載。通過將任何特定的簽名或默認值與調用常規「*」操作符的泛型簽名進行匹配,在呼叫站點解析超載。 – Gustavo

5

如果Point3d類型是在不能修改的單獨程序集中聲明的,則(不幸)無法實現標準運算符的新重載,如+*。您的問題中的代碼將運算符添加爲擴展方法,但在尋找重載運算符時F#編譯器不搜索擴展方法。

如果你不能修改庫,再有三件事情可以做:

  • 創建Point3d的包裝,存儲的Point3d值,並實現了所有運營商
    (但這可能會相當低效)

  • 定義不與內置碰撞的新操作符。例如,可以使用+$$+來從左側和右側乘以標量。要聲明這樣的操作,你可以這樣寫:

    let (+$) (f:float) (a:Point3d) = (...) 
    
  • 實現自己Point3d類型完成所有的工作,這可能與它變成Point3d當你需要調用庫中的轉換功能。

很難說哪個選項是最好的 - 第二種方法可能是最高效的,但會使代碼看起來有點醜。取決於您的方案,選項1或3也可以工作。

+0

我同意你說的一切,但在某些情況下,它也可能是適當的陰影內置運營商而不是創建新的非衝突的(例如,在他們不需要通用的範圍內)。 – kvb

+0

@Tomas:F +不接受(+ $)運營商,我不知道爲什麼。 – Gustavo