Building Enigma with State Monad & Lens

35
Building Enigma with State Monad & Lens Timothy Perrett SF Scala, December 2014

Transcript of Building Enigma with State Monad & Lens

Page 1: Building Enigma with State Monad & Lens

Building Enigma with

State Monad & Lens

Timothy Perrett

SF Scala, December 2014

Page 2: Building Enigma with State Monad & Lens

Hello.

Page 3: Building Enigma with State Monad & Lens
Page 4: Building Enigma with State Monad & Lens

73 years today.

Page 5: Building Enigma with State Monad & Lens

Steckerbrett.(Plugboard)

Page 6: Building Enigma with State Monad & Lens
Page 7: Building Enigma with State Monad & Lens

Walzen. (Rotor)

Page 8: Building Enigma with State Monad & Lens
Page 9: Building Enigma with State Monad & Lens

Umkehrwalze.(Reflector)

Page 10: Building Enigma with State Monad & Lens
Page 11: Building Enigma with State Monad & Lens

Process.

Page 12: Building Enigma with State Monad & Lens
Page 13: Building Enigma with State Monad & Lens

158,962,555,217,826,360,000.(158 quintillion)

Page 14: Building Enigma with State Monad & Lens

Process.

๏ Distributed with typically a month of configuration settings.

๏ Kriegsmarine vessels often had two Enigmas onboard to account for delivery delay due to being submersed

Page 15: Building Enigma with State Monad & Lens

Demo.

Page 16: Building Enigma with State Monad & Lens

Design.

Page 17: Building Enigma with State Monad & Lens

Design.

Page 18: Building Enigma with State Monad & Lens

Design.

Char => Char

Char => Char

Char => CharChar => Char

Page 19: Building Enigma with State Monad & Lens

Code.

Page 20: Building Enigma with State Monad & Lens

case class Plugboard(shuffled: Seq[Char]){ ... }

case class Rotor(

wiring: String,

ring: Char,

notch: Char,

posistion: Char

){ ... }

case class Machine(

plugboard: Plugboard,

right: Rotor,

middle: Rotor,

left: Rotor,

reflector: Reflector

){ ... }

Algebra.

Page 21: Building Enigma with State Monad & Lens

for {

_ <- get[Machine]

_ <- modify((m: Machine) => right(m))

_ <- modify((m: Machine) => middle(m))

_ <- modify((m: Machine) => left(m))

o <- get[Machine]

} yield

o.plugboard.transform _ andThen

rtl(o) andThen

o.reflector.transform andThen

ltr(o) andThen o.plugboard.transform apply(c)

Program.

Page 22: Building Enigma with State Monad & Lens

State.

S => (S, A)

๏ Given a state S, compute a resulting S(i.e. make any needed modifications to the state) and produce a resulting A

๏ Explicit state handling in every type signature can be tedious.

Page 23: Building Enigma with State Monad & Lens

trait State[S,A] {

def get[S]: State[S,S]

def put[S](s: S): State[S, Unit]

def modify[S](f: S => S): State[S, Unit]

def run(s: S): (S,A)

def map[B](f: A => B): State[S,B]

def flatMap[B](f: A => State[S, B]): State[S,B]

}

object State {

def apply[S,A](f: S => (S,A)): State[S, A] =

new State[S,A]{

def run(s: S): (S,A) = f(s)

}

}

State.

Page 24: Building Enigma with State Monad & Lens

trait State[S,A] {

def run(s: S): (S,A)

def map[B](f: A => B): State[S,B] = State { s =>

val (x,a) = run(s)

(x,f(a))

}

def flatMap[B](f: A => State[S, B]): State[S,B] =

State { s =>

val (x,a) = run(s)

f(a).run(s)

}

}

State.

Page 25: Building Enigma with State Monad & Lens

State.

type State[S,A]

๏ State monad threads S through your computation for you.

๏ Actual implementation in Scalaz is in terms of the monad transformer for State through Id.

๏ Avoid overflow by using: type State[S,A] = StateT[Trampoline,S,A]

Page 26: Building Enigma with State Monad & Lens

for {

_ <- get[Machine]

_ <- modify((m: Machine) => right(m))

_ <- modify((m: Machine) => middle(m))

_ <- modify((m: Machine) => left(m))

o <- get[Machine]

} yield

o.plugboard.transform _ andThen

rtl(o) andThen

o.reflector.transform andThen

ltr(o) andThen o.plugboard.transform apply(c)

Program.

Page 27: Building Enigma with State Monad & Lens

def stepRotor(r: Rotor): Rotor =

rotorL.modify(r, Alphabet.nextLetter)

def right(m: Machine): Machine =

m |-> rightL modify(stepRotor)

def middle(m: Machine): Machine =

m |-> middleL modify(r =>

if(m.right.notch == r.position ||

m.left.notch == r.position) stepRotor(r)

else r)

def left(m: Machine): Machine =

m |-> leftL modify(r =>

if(r.position == m.middle.notch) stepRotor(r)

else r)

Program.

Page 28: Building Enigma with State Monad & Lens

Lens.

get: A => B

set: (A,B) => A

๏ Comprised of two functions: “getter” and “setter”, where the latter returns the updated value.

๏ Using lenses, updates compose

Page 29: Building Enigma with State Monad & Lens

m.copy(

right = m.right.copy(

position = m.right.position + 1

),

middle = m.middle.copy(

position = m.middle.position + 1

),

left = m.left.copy(

position = m.left.position + 1

)

)

Lens.

Page 30: Building Enigma with State Monad & Lens

case class Lens[A,B](

get: A => B,

set: (A, B) => A

)

val rotorL = Lens[Rotor, Char](

_.position,

(a, b) => a.copy(position = b)

)

rotorL.set(m.right)

Lens.

Page 31: Building Enigma with State Monad & Lens

Lens.

type Lens[A,B]

๏ Build modular functions to composeupdates to complex domain types.

๏ Scalaz ships with a Lens implementation, but Monocle is really where its at for Lenses

Page 32: Building Enigma with State Monad & Lens

Monocle.

๏ Scalaz Lens is great, but has boilerplate

๏ Monocle removes said boilerplate by using macros

๏ Provides powerful abstractions in the same space as Lens (Prism, Iso, Getter)

๏ Convenient syntax for bedazzlement of lenses

https://github.com/julien-truffaut/Monocle

Page 33: Building Enigma with State Monad & Lens

val lenserM = Lenser[Machine]

val rightL = lenserM(_.right)

val middleL = lenserM(_.middle)

val leftL = lenserM(_.left)

val lenserR = Lenser[Rotor]

val rotorL: Lens[Rotor,Rotor,Char,Char] =

lenserR(_.position)

m |-> rightL |-> rotorL modify(_ + 1)

Monocle.

Page 34: Building Enigma with State Monad & Lens

Roundup.

๏ FP gives you a frame to reason about problems in a straight-forward, explicit and easy manner.

๏ State monad gives you explicit, immutable control over state changes

๏ Lenses make updating nested domain types convenient and composable.

๏ Enigma was an incredible piece of engineering in 1918!

Page 35: Building Enigma with State Monad & Lens

EOF

@timperrett

github.com/timperrett/enigma

timperrett.com