diff --git a/src/main/scala/ScalaPlayground/HigherKindedTypes/DullSolution/DullSolution.scala b/src/main/scala/ScalaPlayground/HigherKindedTypes/DullSolution/DullSolution.scala new file mode 100644 index 0000000..90f17d0 --- /dev/null +++ b/src/main/scala/ScalaPlayground/HigherKindedTypes/DullSolution/DullSolution.scala @@ -0,0 +1,62 @@ +package ScalaPlayground.HigherKindedTypes.DullSolution + +case class User(name: String, age: Int) + +case class IntBox(value: Int): + def map(f: Int => Int): IntBox = new IntBox(f(value)) + def pinch(f: Int => Unit): IntBox = { f(value); this } + +case class StringBox(value: String): + def map(f: String => String): StringBox = new StringBox(f(value)) + def pinch(f: String => Unit): StringBox = { f(value); this } + +case class UserBox(value: User): + def map(f: User => User): UserBox = new UserBox(f(value)) + def pinch(f: User => Unit): UserBox = { f(value); this } + +case class IntCollection(value: Seq[Int]): + def map(f: Int => Int): IntCollection = new IntCollection(value.map(f)) + def pinch(f: Int => Unit): IntCollection = { value.foreach(f); this } + +case class StringCollection(value: Seq[String]): + def map(f: String => String): StringCollection = new StringCollection(value.map(f)) + def pinch(f: String => Unit): StringCollection = { value.foreach(f); this } + +case class UserCollection(value: Seq[User]): + def map(f: User => User): UserCollection = new UserCollection(value.map(f)) + def pinch(f: User => Unit): UserCollection = { value.foreach(f); this } + +object MagicLibrary: + def doItIntBox(container: IntBox)(f: Int => Int): IntBox = + container.map(f).pinch(a => println(s"Pinched: $a")) + + def doItStringBox(container: StringBox)(f: String => String): StringBox = + container.map(f).pinch(a => println(s"Pinched: $a")) + + def doItUserBox(container: UserBox)(f: User => User): UserBox = + container.map(f).pinch(a => println(s"Pinched: $a")) + + def doItIntCollection(container: IntCollection)(f: Int => Int): IntCollection = + container.map(f).pinch(a => println(s"Pinched: $a")) + + def doItStringCollection(container: StringCollection)(f: String => String): StringCollection = + container.map(f).pinch(a => println(s"Pinched: $a")) + + def doItUserCollection(container: UserCollection)(f: User => User): UserCollection = + container.map(f).pinch(a => println(s"Pinched: $a")) + + def doItUserSeq(container: Seq[User])(f: User => User): Seq[User] = + container.map(f).tapEach(a => println(s"Pinched: $a")) + +@main def run(): Unit = + import MagicLibrary.* + + doItIntBox(IntBox(42))(_ + 1) + doItStringBox(StringBox("Hello"))(_ + " World") + doItUserBox(UserBox(User("Alice", 42)))(user => user.copy(name = user.name.toUpperCase)) + + doItIntCollection(IntCollection(Seq(1, 2, 3)))(_ + 1) + doItStringCollection(StringCollection(Seq("Earth", "Mars")))("Hello " + _) + doItUserCollection(UserCollection(Seq(User("Alice", 42), User("Bob", 24))))(user => user.copy(name = user.name.toUpperCase)) + + doItUserSeq(Seq(User("Alice", 42), User("Bob", 24)))(user => user.copy(name = user.name.toUpperCase)) diff --git a/src/main/scala/ScalaPlayground/HigherKindedTypes/GenericSolution/GenericSolution.scala b/src/main/scala/ScalaPlayground/HigherKindedTypes/GenericSolution/GenericSolution.scala new file mode 100644 index 0000000..d09d38b --- /dev/null +++ b/src/main/scala/ScalaPlayground/HigherKindedTypes/GenericSolution/GenericSolution.scala @@ -0,0 +1,33 @@ +package ScalaPlayground.HigherKindedTypes.GenericSolution + +case class User(name: String, age: Int) + +class MyBox[A](val value: A): + def transform[B](f: A => B): MyBox[B] = new MyBox(f(value)) + def pinch(f: A => Unit): MyBox[A] = { f(value); this } + +class MyCollection[A](val value: Seq[A]): + def transform[B](f: A => B): MyCollection[B] = new MyCollection(value.map(f)) + def pinch(f: A => Unit): MyCollection[A] = { value.foreach(f); this } + +object MagicLibrary: + def doItMyBox[A, B](container: MyBox[A])(f: A => B): MyBox[B] = + container.transform(f).pinch(a => println(s"Pinched: $a")) + + def doItMyCollection[A, B](container: MyCollection[A])(f: A => B): MyCollection[B] = + container.transform(f).pinch(a => println(s"Pinched: $a")) + + def doItSeq[A, B](container: Seq[A])(f: A => B): Seq[B] = + container.map(f).tapEach(a => println(s"Pinched: $a")) + +@main def run(): Unit = + import MagicLibrary.{doItMyBox, doItMyCollection, doItSeq} + + doItMyBox(MyBox(42))(_ + 1) + doItMyBox(MyBox("Hello"))(_ + " World") + doItMyBox(MyBox(User("Alice", 42)))(user => user.copy(name = user.name.toUpperCase)) + + doItMyCollection(MyCollection(Seq(1, 2, 3)))(_ + 1) + doItMyCollection(MyCollection(Seq("World", "Mars", "Jupiter")))("Hello " + _) + + doItSeq(Seq(User("Alice", 42), User("Bob", 24)))(user => user.copy(name = user.name.toUpperCase)) diff --git a/src/main/scala/ScalaPlayground/HigherKindedTypes/HktSolution/HktSolution.scala b/src/main/scala/ScalaPlayground/HigherKindedTypes/HktSolution/HktSolution.scala new file mode 100644 index 0000000..44f36e3 --- /dev/null +++ b/src/main/scala/ScalaPlayground/HigherKindedTypes/HktSolution/HktSolution.scala @@ -0,0 +1,46 @@ +package ScalaPlayground.HigherKindedTypes.HktSolution + +case class User(name: String, age: Int) +case class MyBox[A](value: A) +case class MyCollection[A](value: List[A]) + +trait PinchEnabler[F[_]]: + def transform[A, B](container: F[A], f: A => B): F[B] + def pinch[A](container: F[A], f: A => Unit): F[A] + +object MagicLibrary: + def doIt[F[_], A, B](container: F[A])(f: A => B)(using enabler: PinchEnabler[F]): F[B] = + val transformed = enabler.transform(container, f) + enabler.pinch(transformed, a => println(s"Pinched: $a")) + + object OfficialPinchEnablers: + given PinchEnabler[MyBox] with + def transform[A, B](box: MyBox[A], f: A => B): MyBox[B] = MyBox(f(box.value)) + def pinch[A](box: MyBox[A], f: A => Unit): MyBox[A] = { f(box.value); box } + + given PinchEnabler[MyCollection] with + def transform[A, B](c: MyCollection[A], f: A => B): MyCollection[B] = MyCollection(c.value.map(f)) + def pinch[A](c: MyCollection[A], f: A => Unit): MyCollection[A] = { c.value.foreach(f); c } + +@main def run(): Unit = + import MagicLibrary.doIt + import MagicLibrary.OfficialPinchEnablers.given + + doIt(MyBox(42))(_ + 1) + doIt(MyBox("Hello"))(_ + " World") + doIt(MyBox(User("Alice", 42)))(user => user.copy(name = user.name.toUpperCase)) + + doIt(MyCollection(List(1, 2, 3)))(_ + 1) + doIt(MyCollection(List("World", "Mars", "Jupiter")))("Hello " + _) + + val listPincher = new PinchEnabler[List]: + def transform[A, B](arr: List[A], f: A => B): List[B] = arr.map(f) + def pinch[A](arr: List[A], f: A => Unit): List[A] = { arr.foreach(f); arr } + + doIt(List("hello", "world"))(_.toUpperCase)(using listPincher) + + given PinchEnabler[Seq] with + def transform[A, B](s: Seq[A], f: A => B): Seq[B] = s.map(f) + def pinch[A](s: Seq[A], f: A => Unit): Seq[A] = { s.foreach(f); s } + + doIt(Seq(User("Alice", 42), User("Bob", 24)))(user => user.copy(name = user.name.toUpperCase))