Last active
May 25, 2024 10:18
-
-
Save dacr/1b5cd607f483cc89dcc0cd1c58b36bbc to your computer and use it in GitHub Desktop.
scala type class / published by https://github.com/dacr/code-examples-manager #66d83b63-e5bf-42c5-8727-8a6322217af8/c0090b936f4a9a2e6925d8e6810e86577e903c19
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// summary : scala type class | |
// keywords : scala, adt, language-feature, smart-constructor, @testable | |
// publish : gist | |
// authors : David Crosson | |
// license : Apache NON-AI License Version 2.0 (https://raw.githubusercontent.com/non-ai-licenses/non-ai-licenses/main/NON-AI-APACHE2) | |
// id : 66d83b63-e5bf-42c5-8727-8a6322217af8 | |
// created-on : 2021-04-05T17:50:27Z | |
// managed-by : https://github.com/dacr/code-examples-manager | |
// run-with : scala-cli $file | |
// --------------------- | |
//> using scala "3.4.2" | |
// --------------------- | |
// written after [John De Goes - 12 Steps To Better Scala (Part I)](https://youtu.be/71yhnTGw0hY) | |
// PREFER TYPE CLASSES OVER INTERFACES | |
// ---------------------------------------------------------------------- | |
// SO DO NOT WRITE : | |
trait NumberLike[A] {self => | |
def +(that:A):A | |
} | |
// *** BEFORE WITHOUT TYPE CLASS *** | |
case class RationalOO(n: BigInt, d:BigInt) extends NumberLike[RationalOO] { | |
def +(that: RationalOO):RationalOO = RationalOO(n*that.d+that.n*d,d*that.d) | |
} | |
def sumAllOO[A <: NumberLike[A]](l:List[A]):A = l.reduce(_ + _) | |
// so we'll have to support Byte, Short, Int, ... | |
// And comes the limit, we only support types which extends NumberLike ! | |
// This is the limit of the object oriented approach | |
// ===================================================================================== | |
// SO Instead : | |
abstract class Numeric[A] { // A type class with a single operation | |
def add(l: A, r:A):A | |
} // it will exists outside from Rational ! | |
object Numeric { | |
def apply[A](implicit n: Numeric[A]):Numeric[A] = n | |
} | |
implicit class NumericSyntax[A](l: A) { | |
def +(r:A)(implicit n: Numeric[A]) = n.add(l,r) | |
} // the syntax class | |
// *** AFTER THANKS TO TYPE CLASS *** | |
case class Rational(n: BigInt, d:BigInt) // SO HERE NO INHERITANCE TO GIVE THE + CAPABIlITIES | |
// The implementation of the type class | |
implicit val RationalNumeric: Numeric[Rational] = | |
(l: Rational, r: Rational) => Rational(l.n * r.d + r.n * l.d, l.d * r.d) | |
// Thanks to the implicit the new capability is available to the Rational type | |
println(Rational(1,2)+Rational(2,3)) | |
// So we can define a fully generic sumall for all type which "support" Numeric type class ! | |
def sumAll[A: Numeric](l: List[A]): A = l.reduce(_ + _) | |
println(sumAll(List(Rational(1,2), Rational(2,3), Rational(1,7)))) | |
// so for third party data types it becomes straightforward | |
// => just have to define new implicit val such as : | |
implicit val BigIntNumeric: Numeric[BigInt] = (l: BigInt, r: BigInt) => ??? | |
// the interface is removed from the object | |
// so we got a type classes which allow to see similarities between totally different data types | |
// so we can add plus capability even to third parties types ! | |
println("IT WILL BE QUITE EASIER TO DO IN SCALA 3 ! Not so easy in scala 2.x") | |
println("TYPE CLASSES ALLOW TO ABSTRACT ANY DATA TYPES EVEN THOSE COMING FROM THIRD PARTIES !") | |
println("=> A QUITE MORE POWERFUL SOLUTION THAN INTERFACES & OO STYLE !!") | |
// IT BRINGS EVEN MORE THINGS : AUTOMATIC DERIVATION | |
implicit val IntNumeric: Numeric[Int] = (l: Int, r: Int) => l + r | |
implicit def Tuple2Numeric[A: Numeric, B:Numeric]: Numeric[(A, B)] = | |
(l: (A, B), r: (A, B)) => (l(0) + r(0), l(1) + r(1)) // This is the derivation ! | |
println(sumAll((1,1)::(3,4)::(6,9)::Nil)) | |
println(sumAll((1,(1,3))::(3,(11,4))::(6,(13,9))::Nil)) // almost magic ! |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment