I am working with an API that represents points like float * float.
These are inconvenient to do arithmetic on:
let a = (3.0, 4.0)
let b = (2.0, 1.0)
let c = (fst a + fst b, snd a + snd b)
I would like to write:
let c = a + b
I can do this if I define my own type:
type Vector2 =
{
X : float;
Y : float;
}
with
static member (+) (a : Vector2, b : Vector2) =
{ X = a.X + b.X; Y = a.Y + b.Y }
But then I need to convert for the API I am using:
let c = a + b
let cAsTuple = (c.X, c.Y)
Alternatively, I could create a free function:
let add (ax, ay) (bx, by) =
(ax + bx, ay + by)
let c = a |> add b
But this is not quite as nice as true infix operators.
Does F# allow me to define custom operators for tuples?
If you are willing to use a different operator like (+.) you can do this:
let inline (+.) (a,b) (c,d) = (a + c, b + d)
it works with ints, floats, strings:
( 4 , 3 ) +. ( 3 , 2 ) // (7, 5)
( 4., 3.) +. ( 3., 2.) // (7.0, 5.0)
("4", "3") +. ("3", "2") // ("43", "32")
TL;DR; #AMieres answer is the real one, this should rather be a comment but comments are length limited and code formatting is not nice ¯_(ツ)_/¯
There is work in progress to make operator extensions become reality: Issue, RFC, PR Once this is done, the following might finally work:
open System
open System.Runtime.CompilerServices
[<Extension>]
type TupleExtensions() =
[<Extension>]
static member inline (+) ((x1, y1), (x2, y2)) = (x1 + x2, y1 + y2)
// or
type Tuple<'T1, 'T2> with
// warning FS1215: Extension members cannot provide operator overloads.
// Consider defining the operator as part of the type definition instead.
static member inline (+) ((x1, y1), (x2, y2)) = (x1 + x2, y1 + y2)
// and then
let t1 = (1., 2.)
let t2 = (42., 3.141)
TupleExtensions.(+) (t1, t2) // (43.0, 5.141)
// error FS0001: Expecting a type supporting the operator '+' but given a tuple type
t1 + t2
Related
So my team and I have created a function, wordMarkovChain, which generates a random string with nWords words, whose word-pairs are distributed according to the cooccurrence histogram wCooc.
Now we wanted to create a function which will test the newly created wordMarkovChain, so I can confirm that it's working as it should.
The function, diffw2, which compares two cooccurrence histograms as the average sum of squared differences, needs to take in two parameters, c1 and c2, of type wordCooccurrences and return a double, where c1 and c2 are two cooccurrence histograms of M elements such that c1(i, j) is the number
of times word number i is found following word number j.
The math behind the function should look like this: 1/M^2 * Summation from i=0 to M-1 Summation from i=0 to M-1 (c1(i, j) - c2(i, j))^2.
Sorry, I can't post a picture:(
Our two types which we have created seems to be the problem. c1 and c2 can have a different length but the type wordHistogram inside the type wordCoocurence can also have a different length.
The question is, how can we create such a function?
We tried with for loops, but we think it needs to be a recursive function. We are quite new to the whole concept of programming and are looking for some guidance. Please bear in mind that we do not possess vast knowledge of F#, especially not their in build functions.
CODE
// Types
type wordHistogram = (string * int) list
type wordCooccurrences = (string * wordHistogram) list
let diffw2 (c1 : wordCooccurrences) (c2 : wordCooccurrences) : double =
let mutable res = 0
let z1, z2 = c1 |> List.unzip
let z3, z4 = c2 |> List.unzip
let m1 = c1 |> List.length
let m2 = c2 |> List.length
let m = m1 + m2
for i in 0 .. (m - 1) do
for j in 0 .. (m - 1) do
for k in 0 .. ((z2.[j] |> List.length) - 1) do
res <- res + (snd z2.[j].[k] - snd z4.[j].[k]) * (snd z2.[j].[k] - snd z4.[j].[k])
(1.0 / (float(m * m))) * float(res)
This might get you closer to what you need. This could instead be done using recursive functions, but I usually prefer to use built-in higher-order functions like fold or fold2 when they can do the job. See https://msdn.microsoft.com/en-us/visualfsharpdocs/conceptual/list.fold2%5B't1%2C't2%2C'state%5D-function-%5Bfsharp%5D
Each call of List.fold2 receives an "accumulator" with an initial value (or "state") of 0.0. This accumulator is passed to the lambda function in the parameter named "acc". As the lambda is applied to each element of the two input lists, it adds the intermediate result to that acc value, which is then returned as the result of the List.fold2 call.
type wordHistogram = (string * int) list
type wordCooccurrences = (string * wordHistogram) list
let diffw2 (c1 : wordCooccurrences) (c2 : wordCooccurrences) =
let m1 = c1 |> List.length
let m2 = c2 |> List.length
let m = m1 + m2
let res =
(0.0, c1, c2) |||>
List.fold2 (fun acc (_str1, hist1) (_str2, hist2) ->
let intermedRes =
(0.0, hist1, hist2) |||>
List.fold2 (fun acc (_str1, freq1) (_str2, freq2) ->
let diff = float (freq1 - freq2)
acc + diff * diff
)
acc + intermedRes
)
(1.0 / float(m * m)) * res
I think you are trying to do the following
let diffw2_ (c1 : wordCooccurrences) (c2 : wordCooccurrences) =
List.zip c1 c2
|> List.sumBy (fun ((_, w1), (_, w2)) ->
List.zip w1 w2
|> List.sumBy (fun ((_,i1), (_,i2)) ->
(float (i1 - i2)) ** 2.0
)
) |> (fun totalSumOfSquares -> totalSumOfSquares / (c1 |> List.length |> float))
This just returns the average square differences between corresponding elements of c1 and c2. It assumes that c1 and c2 have the same structure.
With F# (and functional programming in general), you typically avoid using mutable variables and for loops, in favor of pure functions.
I've just started learning F# very recently. I have a function which counts the coefficients of the linear equation: y = ax + b, based on coordinates of two points P1(x1, y1), P2(x1, y2). The function looks like this:
module LinearFit
let generate(x1 : double, y1 : double, x2 : double, y2 : double) =
let w = x1 * 1.0 - x2 * 1.0
let wa = y1 * 1.0 - y2 * 1.0
let wb = x1 * y2 - x2 * y1
printfn "w: %g" w
printfn "wa: %g" wa
printfn "wb: %g" wb
let a = wa/w
let b = wb/w
printfn "a: %g" a
printfn "b: %g" b
printfn "%g %g" a b
(a, b)
I'm trying to somehow return founded coefficients as a tuple result and then assign the result to the new variables so later I can use the result to do some other operations. The trivial thing, for now, would be just displayed a result like:
The generated function is y = 2.5x - 6.5
So far I was trying to do sth like this
open System
let main() =
printf "Linear fit"
(a: double, b: double) <- LinearFit.generate(5.0, 6.0, 7.0, 11.0)
printfn "The generated functi..."
main()
Console.ReadKey() |> ignore
This is only a concept as I'm not even able to compile the project as im getting errors:
"Unexpected symbol ',' in expression"
"Unexpected symbol ')' in binding."
I tried to find some similar approach to C#...
For now what I want to achieve is just to assing the result of generate function to some variables. In C# it would look just like
public (double a, double b) Generate(some params here)
{
// some logic here
return (a, b);
}
(var a, var b) = Generate(...);
Any ideas?
You're making several syntactic mistakes.
First, the arrow-left operator <- is destructive update. It takes a mutable variable on the right and an expression on the left, and pushes the value of the expression into the variable. For example:
let mutable x = 5
x <- 42
In your example, neither a nor b are mutable variables that exist by the time you're trying to use the <- operator. Plus, the operator expects a single mutable variable, not a pattern.
Second, the way to declare new variables in F# is with let. It is roughly equivalent to var in C#, except you can declare multiple variables at once by putting them in a pattern. For example:
let x = 42
let pair = (1, 5)
let a, b = pair
Here, on the last line, I'm declaring two variables a and b by destructuring the pair.
In your example, you're trying to introduce the two new variables a and b without a let keyword. This is not allowed.
So, putting all of the above together, this is the right way to do what you're trying to do:
let main() =
printf "Linear fit"
let a, b = LinearFit.generate(5.0, 6.0, 7.0, 11.0)
printfn "The generated functi..."
P.S. Your question betrays a misunderstanding of some pretty basic principles of F# syntax. Because of this, I would recommend that you read through tutorials, examples, and other articles on F# to familiarize yourself with the syntax before attempting to venture farther.
The below is in an F# code snippet where I am trying to remove reliance on the input parameters and perform some sort of function composition:
let h x1 x2 = (*) (exp x1) (sin x2) // how to reduce to point free style
I have tried:
let h1 = (*) exp sin
let h2 = exp * sin
let h3 = ((*) << exp) << sin
Compiler not happy with the first two and the last doesn't yield the desired result.
I am in fact trying to solve the more general problem of function composition (using whatever tools F# has available) summarised as follows:
f1: float -> float
f2: float -> float
f3: float -> float -> float
How to construct h = f3(f1(x),f2(y)) represented mathematically.
There's a generic function LanguagePrimitives.DivideByInt to divide by int without losing generic behavior, we can use it like this:
let inline Divideby2 n = LanguagePrimitives.DivideByInt n 2
val inline Divideby2 :
^a -> ^a when ^a : (static member DivideByInt : ^a * int -> ^a)
But there's no function called MultiplyByInt to perform generic multiplication by int. Is there anything to perform generic multiplication? Like this:
let inline MultiplyBy2 n = SomeGenericFunctionsModule.MultiplybyInt n 2;
P.S. we can always use some non-standard approach like:
let inline MultiplyByInt n m = seq { for i in 1..m -> n} |> Seq.sum
but I'm interested if it is possible to do in the right way.
I'm afraid there's no built-in function, but I can propose two alternative solutions:
type MulExtension = MulExtension of int with
static member (=>) (x:float , MulExtension y) = x * (float y)
static member (=>) (x:decimal, MulExtension y) = x * (decimal y)
static member (=>) (x:int64 , MulExtension y) = x * (int64 y)
// More overloads
let inline MultiplyByInt x y = x => MulExtension y
But you'll have to specify each type.
I would rather use this function:
let inline MultiplyByInt x y =
let fromInt (n:int) : ^a when ^a : (static member (*) : ^a * ^a -> ^a) =
System.Convert.ChangeType(n, typeof<'a>) :?> 'a
x * (fromInt y)
I can't see any difference in performance between both methods.
I managed to get a solution in O(log(N)) which beats yours, but it still feels very ugly
let inline MulInt (m:^t) (n:int) =
let r : ^t ref = ref LanguagePrimitives.GenericZero
let addv : ^t ref= ref LanguagePrimitives.GenericOne
while ((int) !r) < n do
if int(!r + !addv + !addv) < n then
addv := !addv + !addv
else
r := !r + !addv
addv := LanguagePrimitives.GenericOne
!r * m
Using some of the library only features could make this a little better, but would result in warnings.
Note: This solution assumes that n is representable in ^t - i.e.
MulInt 2uy 5000
will loop forever
let inline MultiplyByInt n (x: ^a) =
let zero : ^a = LanguagePrimitives.GenericZero
let one : ^a = LanguagePrimitives.GenericOne
if n = 0 then zero
else
let mutable q, r = System.Math.DivRem(abs n, 2)
let mutable y = x
while q > 0 do
y <- y + y
q <- q / 2
let y = if r = 0 then y else y + x
if n > 0 then y
else y * (zero - one)
I've received an answer from Don Syme (via fsbugs email) when I've asked about missing MutliplyByInt and limited support of DivideByInt:
Don's answer:
This operator exists to support “Seq.averageBy” etc. This represents pseudo-precise division of the total by the count. We didn’t extend the mechanism beyond what was needed for that.
So it looks like I've misunderstood the purpose of this mechanism.
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
Error 15: The type 'float' does not match the type
'Point3d' E:\Work\extension-RW\VS\extension\NXOpen.Extension.FSharp\Module1.fs 18 13 NXOpen.Extension.FSharp
I want to extend the Point3d methods, some new operators. But it doesn't pass over.
If the Point3d type is declared in a separate assembly that you can't modify, then there is (unfortunately) no way to implement new overloads of the standard operators like + or *. The code in your question adds operators as extension methods, but the F# compiler doesn't search for extension methods when looking for overloaded operators.
If you can't modify the library, then there are three things you can do:
Create a wrapper for Point3d that stores a value of Point3d and implements all the operators
(but this is likely going to be quite inefficient)
Define new operators that do not clash with the built-in ones. For example, you can use +$ and $+ for multiplication by scalar from the left and right. To declare such operator, you would write:
let (+$) (f:float) (a:Point3d) = (...)
Implement your own Point3d type that does all the work, possibly with a conversion function that turns it into Point3d when you need to call a library.
It is hard to tell which option is the best - the second approach is probably the most efficient, but it will make code look a bit uglier. Depending on your scenario, the option 1 or 3 may work too.
Indeed it is possible.
There is a way to extend binary operators using the one and only and little known ternary operator ?<-. So in your case you can try this:
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
Now you can try:
> let c=a * b ;;
val c : Point3d = Point3d (1.0,2.0,3.0)
> 2 * 3 ;;
val it : int = 6