6

The Symbolism library overloads arithmetic operators. Although it's written in C# I can use it from F#:

open Symbolism

let x = new Symbol("x")
let y = new Symbol("y")
let z = new Symbol("z")

printfn "%A" (2*x + 3 + 4*x + 5*y + z + 8*y)

the output:

3 + 6 * x + 13 * y + z

However, it also overloads ^ for powers. This of course doesn't play well with F#.

As a step towards a workaround, I exported a method group for powers:

printfn "%A" (Aux.Pow(x, 2) * x)

output:

x ^ 3

How can I overload ** to use the Aux.Pow method group instead?

I can do something like this:

let ( ** ) (a: MathObject) (b: MathObject) = Aux.Pow(a, b)

And that does work for MathObject values:

> x ** y * x;;
val it : MathObject = x ^ (1 + y)

But Aux.Pow is overloaded for int as well:

    public static MathObject Pow(MathObject a, MathObject b)
    { return new Power(a, b).Simplify(); }

    public static MathObject Pow(MathObject a, int b)
    { return a ^ new Integer(b); }

    public static MathObject Pow(int a, MathObject b)
    { return new Integer(a) ^ b; }

Any suggestions welcome!

dharmatech
  • 8,979
  • 8
  • 42
  • 88

2 Answers2

10

You can use the trick described here like this:

open Symbolism

type MathObjectOverloads =
    | MathObjectOverloads 
    static member (?<-) (MathObjectOverloads, a: #MathObject, b: int) = MathObject.op_ExclusiveOr(a, b)
    static member (?<-) (MathObjectOverloads, a: #MathObject, b: #MathObject) = MathObject.op_ExclusiveOr(a, b)
    static member (?<-) (MathObjectOverloads, a: System.Int32, b: #MathObject) = MathObject.op_ExclusiveOr(a, b)

let inline ( ** ) a b = (?<-) MathObjectOverloads a b

let two = Integer(2)
let three = Integer(3)

two ** three

two ** 3

2 ** three

Unlike in the linked answer, we have to use the (?<-) operator because it's the only operator that can take 3 arguments instead of 2, and we need to overload on both the left and right side of the ^ operator

Community
  • 1
  • 1
Gustavo Guerra
  • 5,319
  • 24
  • 42
  • I've been using your `$` trick for some time now, and I'm curious – how did you know of `?<-`, and that it was necessary/appropriate here? Just attention to details in the language spec? – ildjarn Mar 12 '13 at 18:38
  • I learned the `$`trick from the other stackoverflow question I linked, and then I needed an extra parameter and I remembered ?<- took 3 arguments instead of 2. I went to the MSDN docs to see if there was another one, but it seems there isn't – Gustavo Guerra Mar 12 '13 at 19:37
  • 2
    @ildjarn, Gustavo Guerra: for more cases where you can use the ternary operator have a look at this question http://stackoverflow.com/questions/8309620/could-not-extend-operators-in-f/8326906#8326906 . In F# 3.0 you can use static members instead http://stackoverflow.com/questions/4034802/how-would-i-translate-a-haskell-type-class-into-f/8439395#8439395 , then you can have as many parameters as you need, FsControl project in Github uses this technique to emulate typeclasses. – Gus Mar 13 '13 at 06:28
  • 1
    @Gustavo, I tried to use static members instead of the ?<- operator, but couldn't get it to work, I got ambiguity errors, can you add another answer to this question that uses them instead? – Gustavo Guerra Mar 13 '13 at 11:23
  • Sure, here's an example with static members. – Gus Mar 13 '13 at 18:51
5

Here's the same answer but without operators. It works only in F# 3.0 and you can use any number of parameters.

let inline i3 (a:^a,b:^b,c:^c) = ((^a or ^b or ^c) : (static member threeParams: ^a* ^b* ^c -> _) (a,b,c))

open Symbolism

type MathObjectOverloads =
    | MathObjectOverloads 
    static member threeParams (MathObjectOverloads, a: #MathObject , b: int        ) = MathObject.op_ExclusiveOr(a, b)
    static member threeParams (MathObjectOverloads, a: #MathObject , b: #MathObject) = MathObject.op_ExclusiveOr(a, b)
    static member threeParams (MathObjectOverloads, a: System.Int32, b: #MathObject) = MathObject.op_ExclusiveOr(a, b)

let inline ( ** ) a b = i3(MathObjectOverloads, a, b)
Gus
  • 25,839
  • 2
  • 51
  • 76