Upload
timothy-perrett
View
484
Download
1
Embed Size (px)
Citation preview
Building Enigma with
State Monad & Lens
Timothy Perrett
SF Scala, December 2014
Hello.
73 years today.
Steckerbrett.(Plugboard)
Walzen. (Rotor)
Umkehrwalze.(Reflector)
Process.
158,962,555,217,826,360,000.(158 quintillion)
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
Demo.
Design.
Design.
Design.
Char => Char
Char => Char
Char => CharChar => Char
Code.
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.
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.
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.
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.
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.
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]
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.
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.
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
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.
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.
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
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
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.
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!
EOF
@timperrett
github.com/timperrett/enigma
timperrett.com