4 people like it.
Like the snippet!
F# version of Type Classes from OO Perspective
This is the F# translation of the Scala program written for https://functional.works-hub.com/blog/Type-classes-from-OO-perspective. F# doesn't have implicits, so type classes don't work. However, it's interesting to see just how close you can come by passing an instance of the implementation. By flipping the parameters, you can use partial application to create type-specific functions.
Here, we follow the use of the interface, but we could also use statically resolved type parameters to structurally infer different implementations.
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
|
open System
type Shape<'A> =
abstract member Area : 'A -> double
type Circle = Circle of radius:double
type Rectangle = Rectangle of width:double * length:double
let CircleShape =
{ new Shape<_> with
member this.Area(Circle(radius)) = Math.PI * Math.Pow(radius, 2.) }
let RectangleShape =
{ new Shape<_> with
member this.Area(Rectangle(width, length)) = width * length }
let areaOf<'A> (shapeImpl:Shape<'A>) shape = shapeImpl.Area(shape)
|
namespace System
type Shape<'A> =
interface
abstract member Area : 'A -> double
end
Full name: Script.Shape<_>
abstract member Shape.Area : 'A -> double
Full name: Script.Shape`1.Area
Multiple items
val double : value:'T -> double (requires member op_Explicit)
Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.double
--------------------
type double = Double
Full name: Microsoft.FSharp.Core.double
Multiple items
union case Circle.Circle: radius: double -> Circle
--------------------
type Circle = | Circle of radius: double
Full name: Script.Circle
Multiple items
union case Rectangle.Rectangle: width: double * length: double -> Rectangle
--------------------
type Rectangle = | Rectangle of width: double * length: double
Full name: Script.Rectangle
val CircleShape : Shape<Circle>
Full name: Script.CircleShape
val this : Shape<Circle>
abstract member Shape.Area : 'A -> double
val radius : double
type Math =
static val PI : float
static val E : float
static member Abs : value:sbyte -> sbyte + 6 overloads
static member Acos : d:float -> float
static member Asin : d:float -> float
static member Atan : d:float -> float
static member Atan2 : y:float * x:float -> float
static member BigMul : a:int * b:int -> int64
static member Ceiling : d:decimal -> decimal + 1 overload
static member Cos : d:float -> float
...
Full name: System.Math
field Math.PI = 3.14159265359
Math.Pow(x: float, y: float) : float
val RectangleShape : Shape<Rectangle>
Full name: Script.RectangleShape
val this : Shape<Rectangle>
val width : double
val length : double
val areaOf : shapeImpl:Shape<'A> -> shape:'A -> double
Full name: Script.areaOf
val shapeImpl : Shape<'A>
val shape : 'A
More information