2019 Year in Review

I've 2210 commits over the whole year.

Screenshot_2020-01-01 jcouyang - Overview.png

But actually only 450 is for open source, it is been a busy year in MYOB.

3 Layer Scala Cake

By introducing the 3 layer cake concept to Scala, I also published the luci lib to help building extensible Free Monad effects.

Grokking Monad

Screenshot_2020-01-01 Gumroad - Analytics.png

I was not actively updating this book in 2019. I hope all my readers are happy, I was told it is the best book about Category Theory in Chinese. Hoping there will be more time can be focus on updating it in 2020.

Buy one if you can read Chinese and curious about Monad, now examples are available in both Haskell and Scala.

Kleisli{F{_}, -A, B}

I made a change to the Kleisli type so A is now contravariant -A. By Scala subtyping system, we can save a lot of contramaping.

If you want to flatmap different input type of Kleisli before:

val program = for {
  k1 <- Kleisli((a: A1) => List(1)).local(identity[A1 with A2 with A3])
  k2 <- Kleisli((a: A2) => List("2")).local(identity[A1 with A2 with A3])
  k3 <- Kleisli((a: A3) => List(true)).local(identity[A1 with A2 with A3])
} yield (k1, k2, k3)

after cats 2.0 you can just:

val program = for {
  k1 <- Kleisli((a: A1) => List(1))
  k2 <- Kleisli((a: A2) => List("2"))
  k3 <- Kleisli((a: A3) => List(true))
} yield (k1, k2, k3)

since -A is contravariant, Scala can tell the program has type Kleisli[List, A1 with A2 with A3, (Int, String, Boolean)]

The power of Kleisli subtyping lead to a very powerful lib that I recently published for our team - Zhuyu.


With the power of Kleisli, now all kind of effect is composable:

val program = for {
 _ <- effects.Http4s(_.status(GET(uri"https://blog.oyanglul.us")))
 _ <- effects.S3(_.putObject("example-bucket", "filename", "content"))
 _ <- effects.Doobie(sql"select 250".query[Int].unique)
} yield()
// Kleisli[IO, HasHttp4s with HasS3 with HasDoobie, Unit]

More importantly Zhuyu provide a typesafe SQS worker, so you can safely consume messages from SQS, even spread more message back to the SQS, without worry about causing any loop in the queue, because now we can count at type level with shapeless. All these check happen in compile time so you know your code will cause a loop if it didn't compile.

If you need a worker that consume SQS, just

sbt new jcouyang/zhuyu.g8

There is also a simple tutorial video in README

IndexOf at Type Level

Since zhuyu needs to find out the position of a type in coproduct type, I also made change to shapeless so we can find out the index of a specific type in coproduct

  type S = String; type I = Int; type D = Double; type C = Char
  type SIDC = S :+: I :+: D :+: C :+: CNil

    val r1 = IndexOf[SIDC, S].value
    assertTypedEquals(0, r1)

    val r2: Nat = IndexOf[SIDC, I].apply()
    assertTypedEquals(Nat._1, r2)

    val r3 = Coproduct[SIDC](1).indexOf[D]
    assertTypedEquals(Nat._2, r3)

    val r4 = IndexOf[SIDC, C].value
    assertTypedEquals(3, r4)

Type Driven Development with PureScript

We are migrating our production UI codebase from TypeScript to PureScript.

Here is detail why and how.

At the end

  • we have 10% of PureScript on production.
  • code quality are increasing
  • bug rate decreasing
  • members are uplifted with functional programming skill
  • line of code decresing
  • React eco system and purescript coexist well so far

Read the cheatsheet to find out how easy to convert from JS to PureScript

Functional Scala Cachinng

We need to cache a lot of stuff on production, but it is hard to find a caching library with good functional DSL.

So here is my answer Jujiu

It is just Kleisli and with fine with Tagless final as well.

It is easy to compose your caching logic into your existing logic using the DSL , and run it on different interpreter later on. The builtin interpreter is Caffeine and it's easy to add Reddis support as well.


Owlet is now available in ScalaFiddle, please try it out online.