Last active
May 25, 2024 10:19
-
-
Save dacr/ffa5e779d1fa5cb29537fddde754edfe to your computer and use it in GitHub Desktop.
playing with functors / published by https://github.com/dacr/code-examples-manager #9134c469-c58a-41b6-b024-6ff21fd4ce69/9478af7394dffbe47c5aad45cd0b92e621e1a27f
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 : playing with functors | |
// keywords : scala, functor, pure-functional, @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 : 9134c469-c58a-41b6-b024-6ff21fd4ce69 | |
// created-on : 2022-01-22T17:15:13+01:00 | |
// managed-by : https://github.com/dacr/code-examples-manager | |
// run-with : scala-cli $file | |
// --------------------- | |
//> using scala "3.4.2" | |
// --------------------- | |
import scala.util.{Try, Success} | |
// ------------------------------------------------------------ | |
// Inspired from "What the Functor? | Functors in Scala | Rock the JVM" | |
// https://www.youtube.com/watch?v=aSnY2JBzjUw&ab_channel=RocktheJVM | |
// ------------------------------------------------------------ | |
// Definitions | |
// - https://typelevel.org/cats/typeclasses/functor.html : | |
// Functor is a type class that abstracts over type constructors that can be map‘ed over | |
// - https://dzone.com/articles/functors-in-scala | |
// A functor is a type of mapping between categories | |
// ------------------------------------------------------------ | |
// A functor is defined by a type Constructor F[_] together with a function | |
// map :(A=>B) => F[A]=>F[B] | |
// ------------------------------------------------------------ | |
val anIncrementedList = List(1, 2, 3).map(_ + 1) | |
val anOption = Some(2) | |
val aTry = Success(42) | |
val aTransformedOption = anOption.map(_ * 10) | |
val aTransformedTry = aTry.map(_ * 10) | |
// Functors | |
def do10xList(that: List[Int]): List[Int] = that.map(_ * 10) | |
def do10xOption(that: Option[Int]): Option[Int] = that.map(_ * 10) | |
def do10xTry(that: Try[Int]): Try[Int] = that.map(_ * 10) | |
// => Duplicated code here ! | |
// Let's generalize thanks to Functor | |
trait Functor[C[_]]: | |
def map[A, B](container: C[A])(f: A => B): C[B] | |
given listFunctor: Functor[List] with | |
override def map[A, B](container: List[A])(f: A => B): List[B] = container.map(f) | |
//generalize function with a higher kind type => "stable" API | |
def do10x[C[_]](container: C[Int])(using functor: Functor[C]): C[Int] = | |
functor.map(container)(_ * 10) | |
do10x(List(1, 2, 3))(using listFunctor) | |
do10x(List(1, 2, 3)) | |
// ------------------------------------------------------------ | |
sealed trait Tree[+T] | |
object Tree: | |
def leaf[T](value: T): Tree[T] = Leaf(value) | |
def branch[T](value: T, left: Tree[T], right: Tree[T]): Tree[T] = Branch(value, left, right) | |
case class Leaf[+T](value: T) extends Tree[T] | |
case class Branch[+T](value: T, left: Tree[T], right: Tree[T]) extends Tree[T] | |
given treeFunctor: Functor[Tree] with | |
override def map[A, B](container: Tree[A])(f: A => B): Tree[B] = | |
container match | |
case Leaf(value) => Leaf(f(value)) | |
case Branch(value, l, r) => Branch(f(value), map(l)(f), map(r)(f)) | |
import Tree.* | |
val tree = | |
branch(1, branch(2, leaf(3), leaf(4)), leaf(5)) | |
println(do10x(tree)) | |
// ------------------------------------------------------------ | |
extension [C[_], A, B](container: C[A])(using functor: Functor[C]) | |
def map(f: A=>B) = functor.map(container)(f) | |
val tenxTree = tree.map(_ * 10) // treeFunctor.map(tree)(_ * 10) | |
// it extends the original data type | |
println(tenxTree) | |
// ------------------------------------------------------------ | |
println( | |
""" | |
Functors allows us to generalize an API to any kind of data structure | |
in a uniform way without having to repeat ourself ! | |
""" | |
) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment