Skip to content

Instantly share code, notes, and snippets.

@slouc
slouc / ShapelessGenericTypeClassDerivation.scala
Last active May 2, 2017 19:40
ShapelessGenericTypeClassDerivation
import shapeless._
object Basic {
case class Person(firstName: String, age: Int, married: Boolean)
case class Band(name: String, numOfAlbums: Int, stillActive: Boolean)
def personSerialized(p: Person): List[String] = List(p.firstName, p.age.toString, p.married.toString)
def bandSerialized(b: Band): List[String] = List(b.name, b.numOfAlbums.toString, b.stillActive.toString)
import scalaz.Monad
import scalaz._
sealed trait Free[F[_], A] {
def pure(a: A): Free[F, A] = Free.Pure(a)
def lift(f: F[A]): Free[F, A] = Free.Suspend(f)
def flatMap[B](f: A => F[B]): Free[F, B] = Free.Bind[F, A, B](this, f)
def Y[A](func: (A => A) => (A => A)): (A => A) =
func(Y(func))(_)
def factorial: Int => Int =
Y {
(f: Int => Int) =>
(n: Int) =>
if (n <= 0) 1 else n * f(n - 1)
}
@slouc
slouc / ContravariantFunctor.scala
Last active May 3, 2019 09:54
Contravariant functor
case class Money(amount: Int)
// contramap: B => A => F[A] => F[B]
val contramapFn: Money => Int = (money) => money.amount
implicit val moneyOrd: Ordering[Money] = Ordering.by(contramapFn)
import scala.math.Ordered._
println(Money(13) < Money(20)) // true
import cats._
import cats.implicits._
// F[A] can fold A if F is a Foldable and A is a Monoid
def folding[F[_]: Foldable, A: Monoid](fa: F[A]): A =
implicitly[Foldable[F]].fold(fa)
// Option[A] is a Monoid if A is a Semigroup
def foldingOption[A: Semigroup](a: A): Option[A] =
folding(List(Option(a))) // List is Foldable
// add scalacOptions += "-Ypartial-unification" to build.sbt
import scala.reflect.runtime._, universe._
import scala.language.higherKinds
def checkUnification[F[_], A: TypeTag](fa: => F[A]) = s"${typeOf[A]}"
assert(checkUnification(e) == "String")
assert(checkUnification(f) == "List[Int]")
import cats._
abstract class Yoneda[F[_]: Functor, A] { self =>
def apply[B](f: A => B): F[B]
def run: F[A] = apply(identity)
def map[B](f: A => B): Yoneda[F, B] = new Yoneda[F, B] {
def apply[C](g: B => C): F[C] = self.apply(f andThen g)
import scalaz._
import Scalaz._
import scalaz.{Applicative, \/}
def selectA[F[_]: Applicative, A, B](s: F[A \/ B])(f: => F[A => B]): F[B] =
(s |@| f)(_.leftMap(_).merge)
def selectM[F[_]: Monad, A, B](s: F[A \/ B])(f: => F[A => B]): F[B] =
s flatMap {
case -\/(a) => f.map(_(a))
import cats.Functor // scalaz would work as well
// Non recursive data structure
sealed trait ExpressionF[A]
case class ValueF[A](v: Int) extends ExpressionF[A]
case class AddF[A](e1: A, e2: A) extends ExpressionF[A]
case class MultF[A](e1: A, e2: A) extends ExpressionF[A]
// Functor instance for it
import cats._
import cats.implicits._
def foo1[A, B: Semigroup, F[_]: Traverse: Reducible, G[_]: Applicative](
fa: F[A],
fun: A => G[B]
): G[B] =
Traverse[F].traverse(fa)(fun).map(Reducible[F].reduce[B])
// foo2 doesn't need F to be Traverse, but needs G to be FlatMap