F# implementing interfaces with different template parameters [duplicate] - f#

This question already has answers here:
Implementing the same interface at different generic instantiations
(2 answers)
Closed 8 years ago.
Having this code:
type Point2D(x, y) =
member this.X with get() = x
member this.Y with get() = y
interface System.IEquatable<Point2D> with
member x.Equals point =
x.X = point.X
&& x.Y = point.Y
type Point3D(x, y, z) =
inherit Point2D(x, y)
member this.Z with get() = z
interface System.IEquatable<Point3D> with
member x.Equals point =
(x :> System.IEquatable<Point2D>).Equals point
&& x.Z = point.Z
http://take.ms/rjWlJ
I have compile-time. F# is not allow implement the same interface with different template parameter. But I want to implement strongly-typed equals in derived type. So what should I do with it?

No-can-do. Which is a slightly sorry state of affairs, since F# can consume a type with such a design perfectly well when it comes from a different CLR language.
The explanation I heard was that having such a feature was not deemed important, partially because having such a class/interface-heavy design was not considered idiomatic (which I agree with).
So one option you have is implementing those types in C#.
Another more idiomatic way would be to implement them as records:
type Point2D = { x: float; y: float }
type Point3D = { x: float; y: float; z: float }
with
static member FromPoint2D (p: Point2D) = ...
member this.ToPoint2D () = ...
Perhaps add a module with a function for comparing 2d and 3d that will encapsulate the conversion for you.

As the compiler error explains, this isn't supported so the best solution is probably to avoid inheritance in this case and add a member to convert to a 2d point:
type Point3D(x, y, z) =
member this.X with get() = x
member this.Y with get() = y
member this.Z with get() = z
member this.As2D = new Point2D(this.X, this.Y)
interface System.IEquatable<Point3D> with
member x.Equals point =
x.X = point.X && x.Y = point.Y && x.Z = point.Z

Related

F# FS0001: This Expression was expected to have type figure, but her has type int*int

I am currently working on a program that is supposed to take a 'figure' and move it along a vector. For this I have created the function 'move' which takes a 'figure' and a vector.
I am then trying to use pattern-matching to update the values of the figure.
type point = (int*int)
type figure =
|Circle of point * int * string
|Rectangle of point * point * string
|Mix of figure * figure
let circ = Circle((50,50),45,"Red")
let rect = Rectangle((40,40),(90,110),"Blue")
let figTest : figure = Mix(circ,rect)
I have the above types and the starting figure, 'figTest'.
I then call 'move figTest', but it gives the error FS0001: This expression was expected to have type 'figure' but here has type 'int * int -> figure'.
let rec move figure (v:int*int) : figure=
let vx = fst v
let vy = snd v
match figure with
| Circle ((cx,cy) , radius, colour) -> Circle(point(cx + vx, cy-vy), radius, colour)
| Rectangle((x0,y0), (x1,y1), colour) -> Rectangle(point(x0 + vx, y0 + vy),point(x1 + vx, y1 + vy), colour)
| Mix(f1,f2) ->
let newCirc = move(f1)
let newRect = move(f2)
let newFig = Mix(newCirc, newRect)
newFig
The error seems to occur when i give 'newFig' the new circle and rectangle, but I can't quite figure out what is wrong. I struggle quite a bit with these type errors in f# pretty often, so I thought I was getting the hang of it, but I just can't find the cause of this...
This is very close to working, so don't get discouraged. There are two minor problems:
When you call move recursively, you have to pass v again. So let newCirc = move f1 v is correct instead of let newCirc = move(f1). (Note that newCirc might not actually be a circle, so you might want to use a different variable name.)
Since point is just a synonym for int * int, it doesn't have its own constructor function. So (cx + vx, cy-vy) is correct instead of point(cx + vx, cy-vy).
When I made these two changes, your code worked correctly for me. There are a number of other issues with your code that you might want to address, but those are the only two that are show-stoppers at this point.

F# Incomplete Structured Construct Caused By Type Specification

So, I have a function, corners, that I want to take a 2D array (with abbreviated type HieghtMap) and return a list of the record type of Coordinates. Initially, I wasn't specifying matrixLocal's type, which led to
System.Exception: Operation could not be completed due to earlier error
 The type 'matrixLocal' is not defined. at 30,28
Now that I am specifying the type, I get this new error
 Syntax error in labelled type argument at 30,39
Incomplete structured construct at or before this point in
interaction. Expected incomplete structured construct at or before
this point, ';', ';;' or other token.
I believe this is due to farside (as it does not function even on its own), but I do not know why, hence I am here. The other questions that I found regarding the latter error do not seem to apply in this case (one was about indenting, and the other was about trying to redefine a variable in a loop).
The Code:
module DiamondSquare =
//create type for defining shapes
///Defined by length of the side of a square that the ovject is inscribed in
type Shape =
| Square of int
| Diamond of int
///the X and Y position
type Coordinates = {X: int; Y: int}
///The Hieghtmap of a given chunk of region as a series of floats that are the offset from the base hieght
//was HieghtMap = HieghtMap of float[,], but was changed so that any 2D float array would be accepted
type HieghtMap = float[,]
//Create matrix of zeroes of chunk size to initilize this variable
let matrix = Array2D.zeroCreate<float> 9 9
//locate center of shape
// since each shape is a square, or can be inscribed within one, pass it a matrix and find the
// coordinate of the center (same value for i and j)
///Finds center of shape inscribed within a square. Takes a matrix, returns coordinates for within the matrix
let locateCenterpoint matrixLocal =
let coord = int ((Array2D.length1 matrixLocal) - 1) / 2
{X = coord; Y = coord;}
//locate corners of a shape that is inscribed in a square
///Returns list of corner values for a given shape. Takes a matrix and returns a list of Coordinates
let corners shape:Shape matrixLocal:HieghtMap =
let farSide = Array2D.length1 matrixLocal - 1
let getSquareCorners =
{X = 0; Y = 0}::{X = farSide; Y = 0}::{X = 0; Y = farSide}::{X = farSide; Y = farSide}::[]
let getDiamondCorners =
{X = farSide / 2; Y = 0}::{X = farSide; Y = farSide / 2}::{X = farSide / 2; Y = farSide}::{X = 0; Y = farSide / 2}::[]
match shape with
| Square -> getSquareCorners
| Diamond -> getDiamondCorners
| _ -> None
When defining a value in F#, the first colon signifies the end of value names and start of the type declaration. For example:
let f x y : string = ...
In this declaration, string is the return type of the function, and not type of the y parameter. In order to apply type declaration to a single value in the list, use parentheses:
let f x (y: string) = ...
This way, string is the type of y.
For your specific case, look at this line:
let corners shape:Shape matrixLocal:HieghtMap =
See what the problem is? Shape is being parsed as the return type of the corners function, and this makes the subsequent matrixLocal:HeightMap nonsensical. To fix, apply parentheses:
let corners (shape:Shape) (matrixLocal:HieghtMap) =

Method overload with unit of measure

I'm noobing around with F# trying to create overloads of cos that accepts angles with units.
This is my code:
[<Measure>] type rad
[<Measure>] type deg
let toRad(x:float<deg>) =
(float x) * 3.14159265 / 180.0
|> LanguagePrimitives.FloatWithMeasure<rad>
let cos (angle: float<rad>) = cos(float angle)
let cos (angle: float<deg>) = cos(toRad angle) // get duplicate definition of cos here
Compiler complains about duplicate definition of cos on the last row.
Measure types are erased (see the specification), so you effectively have two definitions of cos(angle: float) which causes the error.
You could create a union type for the two possibilities
type Angle = Degrees of float | Radians of float
or give the functions different names.

F# Quadruple Double Function

According to the TryF#.org site this function below returns quadruple of the number entered.
let quadruple x =
let double x = x * 2
double(double(x))
Can anyone explain why as I interpret it as like follows? Quadruple doesn't perform any mutation or multiple calls.
function quadruple(x)
return function double(x)
return x * 2
or C#
int a(int x) { return b(x); }
int b(int x) { return x * 2; }
I think this is just a confused indentation. The function should probably look like this:
let quadruple x =
let double x = x * 2
double(double(x))
This should hopefully make more sense - the quadruple function defines a function double and then calls it on the input x (multiplying it by 2) and then applies double on the result, multiplying it by 2 again, so the result is (x * 2) * 2.
Using the indentation in your sample, the code would not compile, because it is not syntactically valid (a function body cannot end with a let line - it needs to end with an expression representing some result to be returned).

F# type extension with units of measure type conversion resulting in strange error

I have a function that converts from my own implementation of a 3D vector (which supports units of measure) to XNA's implementation:
type Vector3<[<Measure>]'a> with
member inline v.ToXna() =
Microsoft.Xna.Framework.Vector3(v.x / 1.f<_>, v.y / 1.f<_>, v.z / 1.f<_>)
When I compile it, I get a strange error:
The signature and implementation are not compatible because the type
parameter in the class/signature has a different compile-time
requirement to the one in the member/implementation
The inline seems to be a necessity; without it, I get this error:
This construct causes code to be less generic than indicated by the
type annotations. The unit-of-measure variable 'a has been constrained
to be measure 'm'.
Any idea what's going on?
Edit To answer #svick's questions, Vector3 is defined as:
type Vector3<[<Measure>]'u> =
struct
val x:float32<'u>
val y:float32<'u>
val z:float32<'u>
new(x, y, z) = { x = x; y = y; z = z }
end
And I'm also having some type inference problems defining it as a normal function:
let vector3 (v:DumpEngine.Vector3<_>) =
Vector3(v.x / 1.f<_>, v.y / 1.f<_>, v.z / 1.f<_>)
Causes the function to be a Vector3<1> -> Microsoft.Xna.Framework.Vector3, which makes it quite unusable. I'm not sure this is a related issue, though.
Another solution, which circumvents the problem entirely by using a cast rather than a divison:
type Vector3<[<Measure>]'u> with
member inline v.ToXna() =
Microsoft.Xna.Framework.Vector3(float32 v.x, float32 v.y, float32 v.z)
I have no idea what's going on, but this seems to work:
let inline ToXna(v:Vector3<'a>) =
Microsoft.Xna.Framework.Vector3(v.x / 1.f<_>, v.y / 1.f<_>, v.z / 1.f<_>)
It's the best I managed to do, though.

Resources