scala-fp

scala-fp

  • Book
  • GitHub

›Functional Programming

Book

  • Table of contents

Scala

  • Introduction
  • JVM
  • TODO

Functional Programming

  • Introduction
  • Advanced
  • Ecosystem
  • More

Other

  • Haskell
  • Math

Advanced

Resources

  • Functional Programming in Scala (2014) by Paul Chiusano and Runar Bjarnason (Book)
  • Functional Programming, Simplified (2017) by Alvin Alexander (Book)
  • TODO "FP explained to ..." by Marc-Daniel Ortega (Book)(Unpublished)
  • Constraints Liberate, Liberties Constrain by Runar Bjarnason (Video)
  • Scalaz Presentation by Nick Partridge (Video)
  • TODO Functional Structures in Scala by Michael Pilquist (Video)
  • Functional Programming with Effects by Rob Norris (Video)
  • Ladder of Functional Programming

Type Classes

  • Functors, Applicatives, And Monads In Pictures

Show

[ Show | ShowSpec | cats.ShowSpec ]

Show provides textual representation

trait Show[T] {
  def show(value: T): String
}

Eq

[ cats.EqSpec ]

Eq provides equality between two instances of the same type

trait Eq[A] {
  def eqv(x: A, y: A): Boolean
  def neqv(x: A, y: A): Boolean = !eqv(x, y)
}

Semigroup

[ Semigroup | SemigroupSpec | SemigroupLaws | SemigroupLawsProp ]

Semigroup provides combine which must be associative

trait Semigroup[A] {
  def combine(x: A, y: A): A
}

Monoid

[ Monoid | MonoidSpec | MonoidLaws | MonoidLawsProp | cats.MonoidSpec ]

Monoid is a Semigroup with empty which must be an identity element

trait Monoid[A] extends Semigroup[A] {
  def empty: A
}
  • On Monoids
  • fpinscala

Functor

[ Functor | FunctorSpec | FunctorLaws | FunctorLawsProp | cats.FunctorSpec ]

Covariant Functor provides map which encapsulates sequencing computations

trait Functor[F[_]] {
  def map[A, B](fa: F[A])(f: A => B): F[B]
}

The Contravariant functor provides an operation called contramap that represents prepending an operation to a chain

trait Contravariant[F[_]] {
  def contramap[A, B](fa: F[A])(f: B => A): F[B]
}

The Invariant functors provides an operation called imap that is informally equivalent to a combination of map and contramap

trait Invariant[F[_]] {
  def imap[A, B](fa: F[A])(f: A => B)(g: B => A): F[B]
}

Semigroupal

[ cats.SemigroupalSpec ]

Semigroupal allows to combine contexts (Semigroup allows to combine values)

trait Semigroupal[F[_]] {
  def product[A, B](fa: F[A], fb: F[B]): F[(A, B)]
}

Parameters fa and fb are independent effectful values: they can be computed in either order before passing them to product, in contrast to flatMap which imposes a strict order on its parameters

Apply

Apply allows to apply a parameter to a function within a context

trait Apply[F[_]] extends Semigroupal[F] with Functor[F] {
  def ap[A, B](ff: F[A => B])(fa: F[A]): F[B]
}

Applicative Functor

TODO laws

[ Applicative | ApplicativeSpec ]

Applicative allows to lift a value into a context

trait Applicative[F[_]] extends Apply[F] {
  def pure[A](a: A): F[A]
}
  • The Essence of the Iterator Pattern (Paper)
  • Applicative programming with effects (Paper)

Monad

[ Monad | MonadSpec | MonadLaws | MonadLawsProp | cats.MonadSpec ]

A Monad is a mechanism for strictly sequencing effects, also called monadic behaviour

trait Monad[F[_]] extends Applicative[F] {
  // bind or >>=
  def flatMap[A, B](fa: F[A])(f: A => F[B]): F[B]
}
  • Monads for functional programming (Paper)
  • First steps with monads in Scala
  • Demystifying the Monad in Scala
  • Cooking with Monads
  • Refactoring with Monads
  • Monad laws in Scala
  • Monad Tutorial

Everyday monads

  • List
  • Option
  • Either

Identity

[ cats.IdSpec ]

Id monad allows to call monadic methods using plain values

type Id[A] = A

MonadError

[ cats.MonadErrorSpec ]

MonadError abstracts over Either-like data types that are used for error handling and provides extra operations for raising and handling errors

trait ApplicativeError[F[_], E] extends Applicative[F] {
  def raiseError[A](e: E): F[A]
  def handleError[A](fa: F[A])(f: E => A): F[A]
}

trait MonadError[F[_], E] extends ApplicativeError[F, E] with Monad[F] {
  def ensure[A](fa: F[A])(e: E)(f: A => Boolean): F[A]
}
  • Rethinking MonadError

Free Monad

  • Stack Safety for Free (Paper)
  • Stackless Scala With Free Monads (Paper)
  • Move Over Free Monads: Make Way for Free Applicatives! by John de Goes (Video)
  • Stackless Scala
  • Free monads - what? and why?
  • Free Monad examples
  • Overview of free monad in cats
  • Modern Functional Programming [part-1|part-2]

Data Types

It is impossible to combine two arbitrary monads (write a general definition of flatMap) without knowing something about at least one of them. Monad Transformers to the rescue! By convention their name ends with a T suffix

Common Monad Transformers are

  • OptionT for Option
  • EitherT for Either
  • ReaderT for Reader
  • WriterT for Writer
  • StateT for State

Eval

[ cats.EvalSpec ]

Eval monad controls eager, lazy, and memoized evaluation

trait Eval[A] {
  def value: A
  def memoize: Eval[A]
}

One useful property of Eval is that its map and flatMap methods are trampolined. This means that arbitrarily nested calls don't consume stack frames i.e. it's stack safety

Eval monad is a useful tool to enforce stack safety when working on very large computations and data structures. Trampolining is not free although, it avoids consuming stack by creating a chain of function objects on the heap. There are still limits on how deeply computations can be nested, but they are bounded by the size of the heap rather than the stack

State

[ State | StateT | cats.StateSpec ] [ MainState | MainStateT | MainStateTLoop ]

A State[S, A] represents a monadic wrapper of a function S => (S, A)

// IndexedStateT[Eval, S, S, A]
type State[S, A] = StateT[Eval, S, A]

// alias
type StateT[F[_], S, A] = IndexedStateT[F, S, S, A]

class IndexedStateT[F[_], SA, SB, A](val runF: F[SA => F[(SB, A)]])

State monad allows to model mutable state in a purely functional way, without using mutation

sbt "fp/runMain com.github.niqdev.main.MainState"
sbt "fp/runMain com.github.niqdev.main.MainStateT"
sbt "fp/runMain com.github.niqdev.main.MainStateTLoop"
  • ... And Monads for (Almost) All: The State Monad

Writer

[ cats.WriterSpec ]

A Writer[L, V] represents a monadic wrapper of a value (L, V)

type Writer[L, V] = WriterT[Id, L, V]

class WriterT[F[_], L, V](run: F[(L, V)])

Writer monad lets carry a log along with a computation. It's useful to record messages, errors, or additional data about a computation, and extract the log alongside the final result

Kleisli

[ Kleisli | KleisliSpec ]

A Kleisli[F, A, B] represents a monadic wrapper of a function A => F[B]

class Kleisli[F[_], A, B](run: A => F[B])

Kleisli allows to compose functions that return a monadic value

Reader

[ cats.ReaderSpec ]

A Reader[A, B] represents a monadic wrapper of a function A => B

// Kleisli[Id, E, A]
type Reader[A, B] = ReaderT[Id, A, B]

// alias
type ReaderT[F[_], A, B] = Kleisli[F, A, B]

Reader monad allows to sequence operations that depend on some input and one common use is dependency injection

OptionT

[ cats.OptionTSpec ]

A OptionT[F[_], A] represents a monadic wrapper of a value F[Option[A]]

class OptionT[F[_], A](value: F[Option[A]])

OptionT is a monad transformer for Option

Validated

[ cats.ValidatedSpec ]

Validated is similar to Either but allows to accumulate errors

sealed abstract class Validated[+E, +A]
case class Valid[+A](a: A) extends Validated[Nothing, A]
case class Invalid[+E](e: E) extends Validated[E, Nothing]

The Semigroupal implementation of product for a Monad is equivalent to flatMap, which explains why Either, being a Monad provides a fail-fast error handling. On the other side, Validated has an instance of Semigroupal but no instance of Monad, hence the implementation of product is free to accumulate errors

Arrow

TODO

  • Functional Composition

Comonad

TODO

  • A Scala Comonad Tutorial

Effects

Given a monad M[A], if you can not extract the A out of M[A] in a purely-functional way (for Listyou can perform the extraction with List.head) then the monad is called effectful

  • Cats Effect (Documentation)
  • FP to the Max by John De Goes (Video)
  • Intro to Functional Game Programming
  • Incremental Purity (Meetup)
  • TODO Shared State in Functional Programming

IO

[ IO ] [ MainIO | effect.ExampleIO | effect.ExampleIOApp | effect.ExampleResource ]

IO is data type for encoding side effects as pure values

  • The Making of an IO by Daniel Spiewak (Video)
  • An IO monad for cats
  • Monadic IO: Laziness Makes You Free

TODO add more examples

sbt "fp/runMain com.github.niqdev.main.MainIO"

# cats-effect examples
sbt "ecosystem/runMain com.github.niqdev.effect.ExampleIO"
sbt "ecosystem/runMain com.github.niqdev.effect.ExampleIOApp"
sbt "ecosystem/runMain com.github.niqdev.effect.ExampleResource"
sbt "test:testOnly *MyResourceSpec"
← IntroductionEcosystem →
  • Resources
  • Type Classes
    • Show
    • Eq
    • Semigroup
    • Monoid
    • Functor
    • Semigroupal
    • Apply
    • Applicative Functor
    • Monad
    • Free Monad
  • Data Types
    • Eval
    • State
    • Writer
    • Kleisli
    • Reader
    • OptionT
    • Validated
    • Arrow
    • Comonad
  • Effects
    • IO
scala-fp
Contribute
How toGitHub
Copyright © 2022 niqdev