Refactoring using Functional
Design Patterns
Mårten Rånge/Atomize AB
A("capabilityIdentity", Scalar, Iwd(2))
A("txPortMaximumOutputPower", P(dBm0_1, dBm0_1) , ProdDataXml("/board/powerClassUsage"))
A("txPortMaximumPar" , P(dBm0_1, dBm0_1) , SysDataParam("capMaxPar"))
A("txOperationBandLowEdge" , F(kHz, kHz), Gpp3("bandLimits",freqClassUsage).Then(Select(0)))
A("txOperationBandHighEdge", F(kHz, kHz), Gpp3("bandLimits",freqClassUsage).Then(Select(1)))
A("capabilityPortArray", Unspecified, CapabilityPortArray)
String (obviously) Enum Enum What type is this?
A("txOperationBandLowEdge" , F(kHz, kHz), Gpp3("bandLimits",freqClassUsage).Then(Select(0)))
A("txOperationBandHighEdge", F(kHz, kHz), Gpp3("bandLimits",freqClassUsage).Then(Select(1)))
Func<string>
Func<U> Then<T, U>(this Func<T> t, Func<T, U> u)
{
return () => u (t ());
}
Func<string> Gpp3(string path, string id)
Func<string, string> Select(int idx)
Gpp3("bandLimits",freqClassUsage).Then(Select(0))
String (obviously) Enum Enum Func<string>
A("txOperationBandLowEdge" , F(kHz, kHz), Gpp3("bandLimits",freqClassUsage).Then(Select(0)))
A("txOperationBandHighEdge", F(kHz, kHz), Gpp3("bandLimits",freqClassUsage).Then(Select(1)))
Perfect?
Func<string> Gpp3(string path, string key)
{
return () =>
QueryContext.Instance.Gpp3Data.Get (path, key);
}
Func<QueryContext, T>
// When composing we lose the Context
Func<QueryContext, U> Then<T, U>(
this Func<QueryContext, T> t
, Func<T, U> u)
{
return ctx => u(t (ctx));
}
Down the rabbit hole...
type AttributeQuery<'T> = unit -> 'T
type AttributeQuery<'T> = QueryContext -> 'T
val gpp3: string -> string -> AttributeQuery<string>
val prodDataXml: string -> AttributeQuery<string>
val select: int -> string -> AttributeQuery<string>
// type AttributeQuery<'T> = QueryContext -> 'T
let gpp3 path key =
fun ctx -> ctx.Gpp3Data.Get path key
// type AttributeQuery<'T> = QueryContext -> 'T
let select idx s =
fun ctx ->
let vs = s.Split ','
vs.[idx] // TODO: error handling
//Gpp3("bandLimits",freqClassUsage).Then(Select(0))
gpp3 "bandLimits" freqClassUsage ??? select 0
val Bind:
AttributeQuery<'T>
-> ('T -> AttributeQuery<'U>)
-> AttributeQuery<'U>
val Return: 'T -> AttributeQuery<'T>
// type AttributeQuery<'T> = QueryContext -> 'T
let Return v =
fun ctx -> v
// type AttributeQuery<'T> = QueryContext -> 'T
let Bind firstq fsecondq =
fun ctx ->
let first = firstq ctx
let secondq = fsecondq first
let second = secondq ctx
second
let (>>=) firstq fsecondq = Bind firstq fsecondq
//Gpp3("bandLimits",freqClassUsage).Then(Select(0))
gpp3 "bandLimits" freqClassUsage >>= select 0
let bandLimits : AttributeQuery<string> =
gpp3 "bandLimits" freqClassUsage
let hello : AttributeQuery<string> =
select 0 "Hello,There"
let select0 : string -> AttributeQuery<string> =
select 0 // "Hello,There"
let q : AttributeQuery<string> =
bandLimits >>= select0
val Bind:
AttributeQuery<'T> // bandlimits
-> ('T -> AttributeQuery<'U>) // select0
-> AttributeQuery<'U>
val Return: 'T -> AttributeQuery<'T>
// type AttributeQuery<'T> = QueryContext -> 'T
let Bind firstq fsecondq =
fun ctx ->
let first = firstq ctx // bandlimits ctx
let secondq = fsecondq first // select0 first
let second = secondq ctx
second
//Gpp3("bandLimits",freqClassUsage).Then(Select(0))
gpp3 "bandLimits" freqClassUsage >>= select 0
Back to Kansas...
delegate T AttributeQuery<T> (QueryContext ctx);
AttributeQuery<T> Return<T> (T v)
{
return ctx => v;
}
AttributeQuery<U> Bind<T, U> (
this AttributeQuery<T> firstq
, Func<T, AttributeQuery<U>> fsecondq)
{
return ctx => {
var first = firstq (ctx);
var secondq = fsecondq (first);
var second = secondq (ctx);
return second;
};
}
public AttributeQuery<String> Gpp3(string path, string key);
public AttributeQuery<String> ProdDataXml(string path);
public Func<string, AttributeQuery<string>> Select(int idx);
Gpp3("bandLimits",freqClassUsage).Then(Select(0))
Gpp3("bandLimits",freqClassUsage).Bind(Select(0))
String (obviously) Enum Enum AttributeQuery<string>
A("txOperationBandLowEdge" , F(kHz, kHz), Gpp3("bandLimits",freqClassUsage).Bind(Select(0)))
A("txOperationBandHighEdge", F(kHz, kHz), Gpp3("bandLimits",freqClassUsage).Bind(Select(1)))
type AttributeQuery<'T> = QueryContext -> 'T
val Bind:
AttributeQuery<'T>
-> ('T -> AttributeQuery<'U>)
-> AttributeQuery<'U>
val Return: 'T -> AttributeQuery<'T>
Monad
“A monad is a monoid in the category of
endofunctors,
what's the problem?”
Philip Wadler
(Fake but funny)
// Monad type class
// https://wiki.haskell.org/Monad
type M<'T>
val Bind : M<'T> -> ('T -> M<'U>) -> M<'U>
val Return: 'T -> M<'T>
// Monad laws
// https://wiki.haskell.org/Monad_laws
let (>=>) t u = fun v -> Bind (t v) u
Left identity : Return >=> g ≡ g
Right identity: f >=> Return ≡ f
Associativity :
(f >=> g) >=> h
≡
f >=> (g >=> h)
Left identity : x + 0 ≡ x
Right identity: 0 + x ≡ x
Associativity : (x + y) + z ≡ x + (y + z)
The Essence of Monad
”The essence of monad is thus separation of
composition timeline from the composed computation's
execution timeline, as well as the ability of
computation to implicitly carry extra data, as
pertaining to the computation itself, in addition to
its one (hence the name) output, that it will
produce when run (or queried, or called upon).“
https://wiki.haskell.org/Monad
Monads are useful
 We like to define a query to an attribute
 Query implies separation between composition and
execution
 We don’t want to our query to rely on singletons
 Makes testing and composition (if effectful) difficult
 No singletons implies an extra data
 This is the essence of Monads
Experimentation leads to understanding
Common usages for Monads
 Coroutines
 Environment state
 Parsers
 Rules
 Queries
 Tracing
 Transformers
https://github.com/mrange/presentations/
fsharp/ce/turtle
http://www.slideshare.net/martenrange/
monad-a-functional-design-pattern
Questions?

Monad - a functional design pattern