Functional programming for production quality code
description
Transcript of Functional programming for production quality code
![Page 1: Functional programming for production quality code](https://reader035.fdocuments.in/reader035/viewer/2022070302/547e7e785906b5bf718b46a1/html5/thumbnails/1.jpg)
Functional Programming for Production Quality Code
Jack Foxjackfoxy.com craftyThoughts
@foxyjackfox
Slideshttp://www.slideshare.net/jackfoxy
Sample Codehttps://github.com/jackfoxy/Svcc2014Demo
![Page 2: Functional programming for production quality code](https://reader035.fdocuments.in/reader035/viewer/2022070302/547e7e785906b5bf718b46a1/html5/thumbnails/2.jpg)
Functional Programming for Production Quality CodeType
do Success / Failure passing
o Partial Application
o Types, Summation Type, Generic Types
o Pattern Matching
o Modadic Bind
o Function Composition
o Units of Measure (design time types)
o Computation Expressions
o Typing your way into relational data
![Page 3: Functional programming for production quality code](https://reader035.fdocuments.in/reader035/viewer/2022070302/547e7e785906b5bf718b46a1/html5/thumbnails/3.jpg)
Ever seen this code? if condition1 then
doThis()
if condition2 then
doThat()
if condition3 then
doSomeOtherThing()
if condition3 then
aTask()
if condition4 then
anotherTask()
if condition5 then
yetAnotherTask()
if condition5 then
finallyDone()
else handleError()
else handleError()
else handleError()
else handleError()
else handleError()
else handleError()
else handleError()
![Page 4: Functional programming for production quality code](https://reader035.fdocuments.in/reader035/viewer/2022070302/547e7e785906b5bf718b46a1/html5/thumbnails/4.jpg)
Functional Programming
Remember functions from high school math?
f(x) = y
one inputparameter
always mapsto the same
output
![Page 5: Functional programming for production quality code](https://reader035.fdocuments.in/reader035/viewer/2022070302/547e7e785906b5bf718b46a1/html5/thumbnails/5.jpg)
Functional Programming
But I need multiple input parameters!
Remember functions from high school math?
f(x) = y
one inputparameter
always mapsto the same
output
![Page 6: Functional programming for production quality code](https://reader035.fdocuments.in/reader035/viewer/2022070302/547e7e785906b5bf718b46a1/html5/thumbnails/6.jpg)
A compiler FP trick called “currying”
let f x y z =
let w = 1
… //do something
w //return
f(x g(y h(z))) = w
f: x -> (y -> (z -> w))
wrapping single parameter functionswithin functions
function signature
![Page 7: Functional programming for production quality code](https://reader035.fdocuments.in/reader035/viewer/2022070302/547e7e785906b5bf718b46a1/html5/thumbnails/7.jpg)
o You don’t really need to know currying
o Instead understand the inverse of currying
o Unwrap the parameters of a function
o Unwrapping is called “Partial Application”
![Page 8: Functional programming for production quality code](https://reader035.fdocuments.in/reader035/viewer/2022070302/547e7e785906b5bf718b46a1/html5/thumbnails/8.jpg)
o If this is a function
let steamJob temperature barrelsOfSteam wellsToSteam =
…
somethingWeReturn
steamJob : temperature: int -> barrelsOfSteam: int -> wellsToSteam: WellState list -> int
o Then so is this
let mySteamJob = steamJob 500 10000
mySteamJob : (WellState list -> int)
Partial application
![Page 9: Functional programming for production quality code](https://reader035.fdocuments.in/reader035/viewer/2022070302/547e7e785906b5bf718b46a1/html5/thumbnails/9.jpg)
Next: a short digression into types
These are all types
o int
o string
o list
o WellState
o Exception
![Page 10: Functional programming for production quality code](https://reader035.fdocuments.in/reader035/viewer/2022070302/547e7e785906b5bf718b46a1/html5/thumbnails/10.jpg)
Summation type
o This is a type that takes the form of multiple types
o It can only be one of those types at a time
o In F# this type is called “discriminated union”
type Choice<'T1, 'T2> =
| Success of 'T1
| Failure of 'T2note this in not the actual Choice type in Fsharp.Core
![Page 11: Functional programming for production quality code](https://reader035.fdocuments.in/reader035/viewer/2022070302/547e7e785906b5bf718b46a1/html5/thumbnails/11.jpg)
Generic types
type Choice<'T1, 'T2> =
| Success of 'T1
| Failure of 'T2
generic types in type constructor
![Page 12: Functional programming for production quality code](https://reader035.fdocuments.in/reader035/viewer/2022070302/547e7e785906b5bf718b46a1/html5/thumbnails/12.jpg)
Return Summation Type
let steamJob2 (temperature :int) (barrelsOfSteam : int) (wellsToSteam : WellState list) = … if … then
Success wellsToSteam else
Failure (BadSteamJob (sprintf "BadSteamJob temperature %i barrelsOfSteam %i wellsToSteam %A“
temperature barrelsOfSteam wellsToSteam) :> Exception )
(Discriminated Union)
![Page 13: Functional programming for production quality code](https://reader035.fdocuments.in/reader035/viewer/2022070302/547e7e785906b5bf718b46a1/html5/thumbnails/13.jpg)
Return Summation Type
let steamJob2 (temperature :int) (barrelsOfSteam : int) (wellsToSteam : WellState list) = … if … then
Success wellsToSteam else
Failure (BadSteamJob (sprintf "BadSteamJob temperature %i barrelsOfSteam %i wellsToSteam %A“
temperature barrelsOfSteam wellsToSteam) :> Exception )
(Discriminated Union)
steamJob : temperature:int -> barrelsOfSteam:int -> wellsToSteam:WellState list ->Choice<WellState list, Exception>
generic constructor types replaced with real types
![Page 14: Functional programming for production quality code](https://reader035.fdocuments.in/reader035/viewer/2022070302/547e7e785906b5bf718b46a1/html5/thumbnails/14.jpg)
let result = steamJob2 500 4000 wellsToSteam
match result with| Success steamedWells -> printfn "%A" steamedWells| Failure exn -> printfn "%s" exn.Message
steamJob : temperature:int -> barrelsOfSteam:int -> wellsToSteam:WellState list ->Choice<WellState list, Exception>
Consuming a Summation Type(Discriminated Union)
![Page 15: Functional programming for production quality code](https://reader035.fdocuments.in/reader035/viewer/2022070302/547e7e785906b5bf718b46a1/html5/thumbnails/15.jpg)
The tools to pipeline a production process
o Partial application
o Summation type / Coproduct type / Discriminated Union (F#)
o Pattern matching
o Generic types
![Page 16: Functional programming for production quality code](https://reader035.fdocuments.in/reader035/viewer/2022070302/547e7e785906b5bf718b46a1/html5/thumbnails/16.jpg)
The tools to pipeline a production process
o Partial application
o Summation type / Coproduct type / Discriminated Union (F#)
o Pattern matching
o Generic types
o Monadic Bind
![Page 17: Functional programming for production quality code](https://reader035.fdocuments.in/reader035/viewer/2022070302/547e7e785906b5bf718b46a1/html5/thumbnails/17.jpg)
Monadic Bind
let bind nextFunction lastOutput = match lastOutput with | Success s -> nextFunction s | Failure f -> Failure f
bind : nextFunction : ('a -> Choice<'b,'c>) -> lastOutput : Choice<'a,'c> -> Choice<'b,'c>
generic constructor types to be replaced with real types
![Page 18: Functional programming for production quality code](https://reader035.fdocuments.in/reader035/viewer/2022070302/547e7e785906b5bf718b46a1/html5/thumbnails/18.jpg)
Monadic Bind
let bind nextFunction lastOutput = match lastOutput with | Success s -> nextFunction s | Failure f -> Failure f
bind : nextFunction:('a -> Choice<'b,'c>) -> lastOutput:Choice<'a,'c> -> Choice<'b,'c>
the generics line up between nextFunction and lastOutput
resulting output lets us chain indefinitely
![Page 19: Functional programming for production quality code](https://reader035.fdocuments.in/reader035/viewer/2022070302/547e7e785906b5bf718b46a1/html5/thumbnails/19.jpg)
The tools to pipeline a production process
o Partial application
o Summation type / Coproduct type / Discriminated Union (F#)
o Pattern matching
o Generic types
o Monadic Bind
![Page 20: Functional programming for production quality code](https://reader035.fdocuments.in/reader035/viewer/2022070302/547e7e785906b5bf718b46a1/html5/thumbnails/20.jpg)
The tools to pipeline a production process
o Partial application
o Summation type / Coproduct type / Discriminated Union (F#)
o Pattern matching
o Generic types
o Monadic Bind
o Function Composition
![Page 21: Functional programming for production quality code](https://reader035.fdocuments.in/reader035/viewer/2022070302/547e7e785906b5bf718b46a1/html5/thumbnails/21.jpg)
Function Composition
f(x') = w'
g(x'') = w''
h(x''') = w'''h( g( f(x) ) ) = w
![Page 22: Functional programming for production quality code](https://reader035.fdocuments.in/reader035/viewer/2022070302/547e7e785906b5bf718b46a1/html5/thumbnails/22.jpg)
let funcOne x =
let compose = funcOne >> funcTwo
let funcTwo x =
Function Composition
funcTwo : 'T2 -> 'T3
funcOne : 'T1 -> 'T2
( >> ) : ('T1 -> 'T2) -> ('T2 -> 'T3) -> 'T1 -> 'T3
compose: 'T1 -> 'T3
![Page 23: Functional programming for production quality code](https://reader035.fdocuments.in/reader035/viewer/2022070302/547e7e785906b5bf718b46a1/html5/thumbnails/23.jpg)
Putting it all together
let processWells =
steamJob step1Temp step1Bbl
>> bind (acidJob step2Solution step2Bbl)
>> bind (steamJob step3Temp step3Bbl)
>> bind (acidJob step4Solution step4Bbl)
let run() =
match processWells wellsToSteam with
| Success xs -> printfn "success %A" xs
| Failure exn -> printfn "%s" exn.Message
![Page 24: Functional programming for production quality code](https://reader035.fdocuments.in/reader035/viewer/2022070302/547e7e785906b5bf718b46a1/html5/thumbnails/24.jpg)
What could we do better?
o Is there another step we could take to promote correctness?
o There are a lot of parameters.
o Might a programmer easily mix them up in the source code?
![Page 25: Functional programming for production quality code](https://reader035.fdocuments.in/reader035/viewer/2022070302/547e7e785906b5bf718b46a1/html5/thumbnails/25.jpg)
Units of Measureo Design time types over any numeric
type
[<Measure>] type degF // degrees Fahrenheit[<Measure>] type pct // percent[<Measure>] type bbl // barrels[<Measure>] type acidId // acid Id
let step1Temp = 500<degF>let step1Bbl = 10000<bbl>let step2Solution = 25.0<pct>let step2Bbl = 20<bbl>
let steamJob (temp :int<degF>) (bblOfSteam : int<bbl>) (wells : WellState list) =
o Types check at compile time
![Page 26: Functional programming for production quality code](https://reader035.fdocuments.in/reader035/viewer/2022070302/547e7e785906b5bf718b46a1/html5/thumbnails/26.jpg)
o Success / Failure passing
o Partial Application
o Types, Summation Type, Generic Types
o Pattern Matching
o Modadic Bind
o Function Composition
o Units of Measure (design time types)
So Far…
![Page 27: Functional programming for production quality code](https://reader035.fdocuments.in/reader035/viewer/2022070302/547e7e785906b5bf718b46a1/html5/thumbnails/27.jpg)
Async (it’s just another computation expression)
async {
}
The brackets abstracted away a layer of complexity …
…but at a price.*
* We lose function composition.
![Page 28: Functional programming for production quality code](https://reader035.fdocuments.in/reader035/viewer/2022070302/547e7e785906b5bf718b46a1/html5/thumbnails/28.jpg)
Async (it’s frequently about plumbing)
async {
}
http://commons.wikimedia.org/wiki/File:PSM_V33_D306_Plumbing_arrangement_in_a_19th_century_new_york_house.jpg
![Page 29: Functional programming for production quality code](https://reader035.fdocuments.in/reader035/viewer/2022070302/547e7e785906b5bf718b46a1/html5/thumbnails/29.jpg)
let productModel name = async {
let! result = asyncChoice {
let! productId = productIdByName name
let! prodDescription = productAndDescription productI
let containsFoo = prodDescription.Description.Contains("foo")
if containsFoo then
return! async { return Failure ( OutOfBounds("Don't show customers foo")) }
else
let descriptionWords = prodDescription.Description.Split(" ".ToCharArray())
let! productId2 = productIdByName descriptionWords.[0]
let! prodDescription2 = productAndDescription productId2
return prodDescription2.ProductModel
}
match result with
| Success x -> return Success x
| Failure exn -> return Failure ex
}
![Page 30: Functional programming for production quality code](https://reader035.fdocuments.in/reader035/viewer/2022070302/547e7e785906b5bf718b46a1/html5/thumbnails/30.jpg)
AsyncChoicebuilder *
member __.Bind …
member __.Combine (r1, r2) : Async<Choice<'T, 'Error>> =
async {
let! r1' = r1
match r1' with
| Choice1Of2 () ->
return! r2
| Choice2Of2 error ->
return Choice2Of2 error
}* ExtCore
![Page 31: Functional programming for production quality code](https://reader035.fdocuments.in/reader035/viewer/2022070302/547e7e785906b5bf718b46a1/html5/thumbnails/31.jpg)
asyncChoice {
let! productId = productIdByName name
let! prodDescription = productAndDescription productI
let containsFoo = prodDescription.Description.Contains("foo")
if containsFoo then
return! async { return Failure ( OutOfBounds("Don't show customers foo")) }
else
let descriptionWords = prodDescription.Description.Split(" ".ToCharArray())
let! productId2 = productIdByName descriptionWords.[0]
let! prodDescription2 = productAndDescription productId2
return prodDescription2.ProductModel
}
binds to value inside the builder
returns the value inside the computation expression
choice builder’s combine composes bound values
inside “choice”
“inbetween” regular F# syntax and control
statements
![Page 32: Functional programming for production quality code](https://reader035.fdocuments.in/reader035/viewer/2022070302/547e7e785906b5bf718b46a1/html5/thumbnails/32.jpg)
Typing your way into relational data
o FSharp.Data.SqlClient
type ProductIdByName = SqlCommandProvider<"
SELECT ProductID from Production.Product
WHERE Name = @name
", connectionString, SingleRow = true>
write any T-SQL inline, “red
squigglies” from compiler on syntax and schema errors
optional parameter
![Page 33: Functional programming for production quality code](https://reader035.fdocuments.in/reader035/viewer/2022070302/547e7e785906b5bf718b46a1/html5/thumbnails/33.jpg)
FSharp.Data.SqlClient
let productIdByName name = async {
let! result =
async {
use cmd = new ProductIdByName()
return! cmd.AsyncExecute(name = name)
}
|> Async.Catch
match result with
| Choice1Of2 (Some productID) -> return Success productID
| Choice1Of2 _ -> return Failure ( SelectNotFound() :> Exception )
| Choice2Of2 exn -> return Failure exn
return type is a record strongly
typed to result of query
parameters indicated by intellisense
in this case return type is option
![Page 34: Functional programming for production quality code](https://reader035.fdocuments.in/reader035/viewer/2022070302/547e7e785906b5bf718b46a1/html5/thumbnails/34.jpg)
Programmability over functions and sprocs
[<Literal>]
let connectionString = @"Data Source=.;Initial Catalog=AdventureWorks2012;Integrated Security=SSPI"
type AdventureWorks = SqlProgrammabilityProvider<connectionString>
type Dbo = AdventureWorks.dbo
type BillOfMaterials = AdventureWorks.dbo.uspGetBillOfMaterials
let cmd = new BillOfMaterials()
cmd.AsyncExecute(1, DateTime.UtcNow) |> Async.RunSynchronouslyreturn type strongly typed to
result
parameters indicated by intellisense
intellisense dot
completion
![Page 35: Functional programming for production quality code](https://reader035.fdocuments.in/reader035/viewer/2022070302/547e7e785906b5bf718b46a1/html5/thumbnails/35.jpg)
SQL Enumeration
type ProductCategory = SqlEnumProvider<"
SELECT Name, ProductCategoryID
FROM Production.ProductCategory", connectionString>
let AccessoriesId = ProductCategory.Accessories
intellisense dot
completion
![Page 36: Functional programming for production quality code](https://reader035.fdocuments.in/reader035/viewer/2022070302/547e7e785906b5bf718b46a1/html5/thumbnails/36.jpg)
o Success / Failure passing
o Partial Application
o Types, Summation Type, Generic Types
o Pattern Matching
o Modadic Bind
o Function Composition
o Units of Measure (design time types)
o Computation Expressions
o Typing your way into relational data
What we covered
![Page 37: Functional programming for production quality code](https://reader035.fdocuments.in/reader035/viewer/2022070302/547e7e785906b5bf718b46a1/html5/thumbnails/37.jpg)
Questions?Bibliographyo Railway oriented programming
http://fsharpforfunandprofit.com/posts/recipe-part2/
o Computation Expressionshttp://msdn.microsoft.com/en-us/library/dd233182.aspx
o The F# Computation Expression Zoohttp://tomasp.net/academic/papers/computation-zoo/computation-zoo.pdf
o ExtCore, an extended core library for F#https://github.com/jack-pappas/ExtCore
o FSharp.Data.SqlClienthttp://fsprojects.github.io/FSharp.Data.SqlClient/
Code: github.com/jackfoxy/Svcc2014Demo Slides: www.slideshare.net/jackfoxy