Skip to content

Instantly share code, notes, and snippets.

trait Shape[A] {
def area(a: A): Double
}
case class Circle(radius: Double)
case class Rectangle(width: Double, length: Double)
// Here >
implicit object CircleShape extends Shape[Circle] {
override def area(circle: Circle) : Double = math.Pi * math.pow(circle.radius, 2)
// vvvvvvvvvvvv (new parameter)
def areaOf[A](shapeInfo: A, shape: Shape[A]): Double = shape.area(shapeInfo)
areaOf(Circle(10), new CircleShape)
trait Shape {
def area: Double
def info: String
}
class Circle(radius: Double) extends Shape {
override def area: Double = math.Pi * math.pow(radius, 2)
override def info: String = s"Hi, I'm a circle with radius $radius"
trait Shape {
def area: Double
}
trait Printable {
def info: String
}
class Circle(radius: Double) extends Shape with Printable {
override def area: Double = math.Pi * math.pow(radius, 2)
val lazyOption: LazyFunctor[Option, Int] = toLazyFunctor(Some(42))
val transformed: LazyFunctor[Option, Int] = lazyOption.map(_ + 1).map(_ + 2) // silly example
// nothing is executed yet
// apply all transformations at once, yields Some(45)
val option: Option[Int] = fromLazyFunctor(transformed)
sealed trait LazyFunctor[F[_], A] {
// takes a function and applies it to original value
def transformation[B](f: A => B): F[B]
// interace 'map' to be used as functor
def map[B](f: A => B): LazyFunctor[F, B] = ???
}
// lets also make it an abstrac class and add self type annotation
abstract class LazyFunctor[F[_], A] { self =>
// function to be applied when we call "run"
def transformation[B](f: A => B): F[B]
// interace 'map' to be used as functor
def map[B](f: A => B): LazyFunctor[F, B] = new LazyFunctor[F, B] {
def transformation[C](g: B => C): F[C] = self.transformation(g compose f)
}
}
abstract class LazyFunctor[F[_], A] { self =>
// should be implemented as a composition of transformations
def transformation[B](f: A => B): F[B]
// apply transformations and get our value back
def run: F[A] = transformation(identity)
// interace 'map' to be used as functor
def map[B](f: A => B): LazyFunctor[F, B] = new LazyFunctor[F, B] {
def transformation[C](g: B => C): F[C] = self.transformation(g compose f)
def toLazyFunctor[F[_], A](fa: F[A]): LazyFunctor[F, A] = ???
def fromLazyFunctor[F[_], A](lf: LazyFunctor[F, A]): F[A] = lf.run
// vvvvvvvvvvvvvvvvvvvvvv
def toLazyFunctor[F[_], A](fa: F[A])(implicit F: Functor[F]): LazyFunctor[F, A] =
new LazyFunctor[F, A] {
override def transformation[B](f: (A) => B): F[B] = F.map(fa)(f)
}
def fromLazyFunctor[F[_], A](lf: LazyFunctor[F, A]): F[A] = lf.run