Skip to content

Instantly share code, notes, and snippets.

View julien-truffaut's full-sized avatar

Julien Truffaut julien-truffaut

View GitHub Profile
@julien-truffaut
julien-truffaut / Auth.scala
Last active May 10, 2021 11:29
Auth middleware issue
trait Auth {
def authenticate(token: Token): Future[User]
}
class OktaAuth(client: RestClient) extends Auth {
def authenticate(token: Token): Future[User] = ???
}
class MockAuth(users: Map[Token, User]) extends Auth {
def authenticate(token: Token): Future[User] = ???
@julien-truffaut
julien-truffaut / SIP-type-alias.MD
Created June 5, 2020 12:57
SIP proposal for using type alias in type inference and error messages

Problem

ZIO, fs2 and other libraries found out that a natural encoding in Scala relies on multiple type parameters with variance (I believe John called this effect rotation):

  • ZIO[-R, +E, +A]
  • fs2.Stream[F[_], +A]
  • Optic[+E, -S, +T, +A, -B] or even more type parameters if include index optics

With this encoding, we can express the absence of error (E = Nothing), absence of effect (F = Nothing), absence of environment variables (R = Any) and all this with perfect type inference. So it is a big win on all fronts except for function signatures and error messages. As we can end-up with an Optic[Nothing, User, User, String, String] instead of Lens[User, String] or

@julien-truffaut
julien-truffaut / SIP-type-alias.MD
Created June 3, 2020 08:24
SIP proposal for using type alias in type inference and error messages

Hi all,

Yilin recently had an idea for a SIP proposal for Scala 3 that I think would benefit to Monocle, ZIO and probably the rest of the Scala ecosystem. It is quite a vague concept at the moment, but I thought it would be worth getting your inputs.

Problem: ZIO, fs2 and other libraries found out that a natural encoding in Scala relies on multiple type parameters with variance (I believe John called this effect rotation):

  • ZIO[-R, +E, +A]
  • fs2.Stream[F[_], +A]
  • Optic[+E, -S, +T, +A, -B] or even more type parameters if include index optics
@julien-truffaut
julien-truffaut / friendlyOptics.MD
Last active September 16, 2020 05:16
Proposal for new optics names

Frieldly optics name proposals

Here are some proposal for optics names. The goal is to give a better intuition to beginners, especially people with no FP experience.

  • Setter -> Replace, Modify, Write
  • Fold -> Aggregate
  • NonEmptyFold -> Reduce
  • Getter -> Read
  • ReadOnlyOptional -> ???
@julien-truffaut
julien-truffaut / Monocle3.MD
Last active July 7, 2022 09:31
Monocle 3.x

We recently started the development of the next major version of Monocle, Monocle 3.x. In this post, I would like to explain our objectives and discuss some of the changes we intend to make.

Monocle 3.x will be a complete rewrite. It doesn't mean we will change everything, but we will question every aspect of the library: optics encoding, API, names, dependencies, etc. We defined the following objectives to help us make trade-offs in the new design:

  1. User-friendly interface. A user should be able to perform the most common actions without requiring in-depth knowledge of optics.
  2. Correctness. Optics follow certain essential principles. Those rules may not be intuitive, but without them, optics would not be a useful abstraction. The API should make it easy to follow those principles and avoid any undesired behaviours.
  3. Focus on Scala 3. We should design the API and include features such as they are suitable for Scala 3.
  4. Performance. Optics are slower than handwritten equivalent code
@julien-truffaut
julien-truffaut / part1.MD
Last active December 18, 2019 14:08
What I learnt writing a functional programming course

Around a year ago, I started working on one of my most significant projects: a functional programming training course. As the year ends, it is a good time for introspection. In this post, I will analyse what worked out and what didn't. Hopefully, my experience can help other people who intend to prepare and run workshops.

Summary

The course is called Foundation, and all the content is available on GitHub at https://github.com/fp-tower/foundation. It contains four modules that roughly take 4-5 hours to go through. I wrote two additional modules which require a more experienced audience in functional programming, so I moved them to another repository https://github.com/fp-tower/abstraction.

At the moment I am writing this article, I run the course seven times using various configurations: monthly 2-hour workshop, 2-day course (consecutive days or not), on-site or remote.

What I did wrong

@julien-truffaut
julien-truffaut / StateOfMonocle.MD
Last active December 18, 2019 14:06
State of Monocle

Monocle, like many other Scala FP libraries, was inspired by Haskell. In our case, it is the Lens library by Edward Kmett and al.

In Monocle, we experimented with various optics encoding: pair of functions, Van Laarhoven, and profunctor (see LensImpl). The JVM and Haskell runtime are hugely different, and an encoding that works well in Haskell can be inefficient in Scala. For example, Haskell relies on zero cost wrapper (newtype) to effectively select typeclass instances, but we don't have an equivalent in Scala/JVM yet (opaque types may help). You can find some of the benchmarks we made for Lenses in 2015 here.

However, something we didn't do very well was to adapt the API to the specificity of Scala. If you look at Monocle 1.x or 2.x, it has the same interface as Haskell Lens but expressed in a much more clunky wa

trait Example {
import cats.implicits._
import cats.~>
type VdomNode
type StateSnapshot[A]
type Lens[S, A]
type Layout1 = VdomNode => VdomNode
type Layout2 = (VdomNode, VdomNode) => VdomNode
@julien-truffaut
julien-truffaut / docker.MD
Last active July 18, 2019 13:36
Docker cheat sheet
docker kill $(docker ps -q)    # stop all containers
docker rm $(docker ps -a -q)   # remove all containers
docker rmi $(docker images -q) # remove all docker images
import cats.Monad
import cats.data.EitherT
import cats.implicits._
import cats.mtl.implicits._
import cats.mtl.{ApplicativeAsk, FunctorRaise}
import doobie.free.connection.ConnectionIO
object MtlExample {
case class RequestId(value: String)