Skip to content

Instantly share code, notes, and snippets.

View kailuowang's full-sized avatar

Kai(luo) Wang kailuowang

View GitHub Profile
@gvolpe
gvolpe / shared-state-in-fp.md
Last active March 15, 2022 20:27
Shared State in pure Functional Programming

Shared State in pure Functional Programming

Newcomers to Functional Programming are often very confused about the proper way to share state without breaking purity and end up having a mix of pure and impure code that defeats the purpose of having pure FP code in the first place.

Reason why I decided to write up a beginner friendly guide :)

Use Case

We have a program that runs three computations at the same time and updates the internal state to keep track of the

/*
* Copyright 2017 Daniel Spiewak
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
Type Functor Apply Applicative Bind Monad MonoidK MonadError Cobind Comonad
Id[A]
Option[A]
Const[K, A] ✔ (K:Monoid) ? ?
Either[E, A]
List[A]
NonEmptyList[A]
@atamborrino
atamborrino / sparkEc.scala
Last active December 10, 2020 16:01
Serializable Scala ExecutionContext for Spark. Allows to automatically re-create a thread-pool per Spark worker.
class ECProvider()(implicit conf: Config) extends Serializable {
@transient implicit lazy val ec: ExecutionContext = {
ExecutionContext.fromExecutorService(
Executors.newWorkStealingPool(conf.getForkJoinPoolMaxParallelism())
)
}
}

Explaining Miles's Magic

Miles Sabin recently opened a pull request fixing the infamous SI-2712. First off, this is remarkable and, if merged, will make everyone's life enormously easier. This is a bug that a lot of people hit often without even realizing it, and they just assume that either they did something wrong or the compiler is broken in some weird way. It is especially common for users of scalaz or cats.

But that's not what I wanted to write about. What I want to write about is the exact semantics of Miles's fix, because it does impose some very specific assumptions about the way that type constructors work, and understanding those assumptions is the key to getting the most of it his fix.

For starters, here is the sort of thing that SI-2712 affects:

def foo[F[_], A](fa: F[A]): String = fa.toString
// allows converting one class to another by providing missing fields
object convert {
@annotation.implicitNotFound("""
You have not provided enough arguments to convert from ${In} to ${Out}.
${Args}
""")
trait Convertible[Args, In, Out] {
def apply(args: Args, in: In): Out
}
@milessabin
milessabin / gist:cadd73b7756fe4097ca0
Last active September 16, 2019 13:44
A new approach to encoding dependently-typed chained implicits, using singleton types ...
object Demo {
// A couple of type classes with type members ...
trait Foo[T] {
type A
}
object Foo {
implicit val fooIS = new Foo[Int] { type A = String }
}