- purity is a syntactical property of programs, more precisely defined as referential transparency: replacing an expression for its bound value doesn't change meaning (precise definition)
- side effects are things that break referential transparency (precise definition)
- There's no direct connection between the concepts of IO, State and so on, and side effects. Traditionally, these things are side effectful (break referential transparency), but you can have abstractions that are pure (don't break ref.trans.)
- Due to the above, the term purely functional programming is not an oxymoron, it makes perfect sense.
- In haskell style pure FP, type constructors and algebras are used to represent "things that would otherwise traditionally be side effects (break ref.trans.)". We call these F[_]s effects or computational contexts for brevity. You can see for yourself how this cannot be a precise definition (especially because they could also have kind higher than * -> *, even though most famous a
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def shortCircuitFutureList[A](fs: List[() => Future[A]], cond: A => Boolean)( | |
implicit executionContext: ExecutionContext): Future[A] = fs match { | |
case tail :: Nil => tail() | |
case head :: _ => | |
head() | |
.filter(cond) | |
.recoverWith { | |
case _ => shortCircuitFutureList(fs.tail, cond) | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def myBusinessStuff(...) = { | |
// Implementations and explicit names | |
val action1 = ??? | |
val action2 = ??? | |
val action3 = ??? | |
// What business people should almost be able to understand | |
for { | |
_ <- action1 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
implicit class InfixMappable[A, B, C](f: A => B) { | |
def `<$>`[G[_]: Functor](ga: G[A]): G[B] = Functor[G].map(ga)(f) | |
} | |
val ap1: Option[Int] = ??? | |
val ap2: Option[Int] = ??? | |
val ap3: Option[Int] = ??? | |
val f: Int => Int => Int => Int = ??? | |
f `<$>` ap1 ap ap2 ap ap3 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
object EnvEffetWithoutSubtyping { | |
import EnvEffetWithoutSubtyping.Alg1.HasAlg1 | |
import EnvEffetWithoutSubtyping.Alg2.HasAlg2 | |
import EnvEffetWithoutSubtyping.Alg3.HasAlg3 | |
trait Alg1 | |
object Alg1 { | |
// Describe an env intersection type which contains an Alg1 type | |
trait HasAlg1[E] { |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
object EnvEffetWithoutSubtyping { | |
import EnvEffetWithoutSubtyping.Alg1.HasAlg1 | |
import EnvEffetWithoutSubtyping.Alg2.HasAlg2 | |
import EnvEffetWithoutSubtyping.Alg3.HasAlg3 | |
trait Alg1 | |
object Alg1 { | |
trait HasAlg1[E] { | |
def alg1(e: E): Alg1 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
object BoilerPlate { | |
// Some random effect type classes we'll want to stack (MTL) | |
trait IOEffect[F[_]] | |
trait StateEffect[F[_]] | |
// Our "final" type that match our needs, providing the typeclass instances needed by our algebras implementations | |
// It's often a monad transformer stack or custom type classes implementations | |
type MyF[A] | |
implicit def myFIO: IOEffect[MyF] = ??? |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
object Validation extends App { | |
object FailFast { | |
def validationEven(i: Int): Either[String, Int] = if (i % 2 == 0) Right(i) else Left("Odd") | |
def validationLT100(i: Int): Either[String, Int] = if (i < 100) Right(i) else Left("GT 100") | |
def validationGT0(i: Int): Either[String, Int] = if (i > 0) Right(i) else Left("LT 0") | |
def validation(i: Int): Either[String, Int] = | |
for { | |
_ <- validationEven(i) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
trait MonadReader[R, F[_]] { | |
def read: F[R] | |
} | |
trait HasEnv1[R] { | |
def env1: Lens[R, LowDslEnv1] | |
} | |
case class LowDslEnv1() | |
def myLowDsl1[R: HasEnv1, F[_]: MonadReader[R, ?]]: F[Unit] = ??? | |
trait HasEnv2[R] { |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
object HigherOrderAbstractSyntax { | |
/** | |
* Let's write a language which supports: | |
* | |
* let i = 0 | |
* in while (i < 10) { i = i + 1 } | |
*/ | |
trait Expr[F[_]] { | |
def intLit(value: Int): F[Int] | |
def add(l: F[Int], r: F[Int]): F[Int] |
NewerOlder