3 people like it.

F# SRTP of Type Classes from OO Perspective

Similar to http://fssnip.net/7Tr, this implementation translates the Scala from https://functional.works-hub.com/blog/Type-classes-from-OO-perspective but uses statically resolved type parameters to show how something similar could be done with computation expression instances. It's really too bad you have to pass an instance of the implementation. It would be nice to be able to specify a module or class with a static member.

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
open System

type Circle = Circle of radius:double
type Rectangle = Rectangle of width:double * length:double

type CircleShape() =
    member this.Area(Circle(radius)) = Math.PI * Math.Pow(radius, 2.)
let circleShape = CircleShape()

type RectangleShape() =
    member this.Area(Rectangle(width, length)) = width * length
let rectangleShape = RectangleShape()

let inline areaOf shapeImpl shape =
    ( ^T : (member Area : 'A -> double) (shapeImpl, shape))
namespace System
Multiple items
union case Circle.Circle: radius: double -> Circle

--------------------
type Circle = | Circle of radius: double

Full name: Script.Circle
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 Rectangle.Rectangle: width: double * length: double -> Rectangle

--------------------
type Rectangle = | Rectangle of width: double * length: double

Full name: Script.Rectangle
Multiple items
type CircleShape =
  new : unit -> CircleShape
  member Area : Circle -> float

Full name: Script.CircleShape

--------------------
new : unit -> CircleShape
val this : CircleShape
member CircleShape.Area : Circle -> float

Full name: Script.CircleShape.Area
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 circleShape : CircleShape

Full name: Script.circleShape
Multiple items
type RectangleShape =
  new : unit -> RectangleShape
  member Area : Rectangle -> double

Full name: Script.RectangleShape

--------------------
new : unit -> RectangleShape
val this : RectangleShape
member RectangleShape.Area : Rectangle -> double

Full name: Script.RectangleShape.Area
val width : double
val length : double
val rectangleShape : RectangleShape

Full name: Script.rectangleShape
val areaOf : shapeImpl:'T -> shape:'A -> double (requires member Area)

Full name: Script.areaOf
val shapeImpl : 'T (requires member Area)
val shape : 'A

More information

Link:http://fssnip.net/7Ts
Posted:7 years ago
Author:Ryan Riley
Tags: trait