Functional programming principles

35
Functional Programming Patterns Andrey Denisov, Paragonex Team Practices ?

Transcript of Functional programming principles

Page 1: Functional programming principles

Functional Programming Patterns

Andrey Denisov, Paragonex Team

Practices ?

Page 2: Functional programming principles
Page 3: Functional programming principles

OO-pattern/principle• Factory pattern

• Strategy pattern

• Decorator pattern

• Facade pattern

• Single Responsibility principle

FP equivalent

• Functions

• Functions

• Functions

• Functions

• Functions

Page 4: Functional programming principles
Page 5: Functional programming principles

ImmutabilityPure functions

Partial application/Currying

Function composition

Functional dependency injection

Page 6: Functional programming principles

class Point { var x = 0.0 var y = 0.0 init(x : Double, y : Double) { self.x = x self.y = y } func scale (factor : Double) { self.x = self.x * factor self.y = self.y * factor }}

Page 7: Functional programming principles

var p = Point(x: 1.0, y: 1.0)var q = p

q.scale(factor: 5) p.scale(factor: 3) // 3.0 3.0 ?

print(p.x, p.y) // 15.0 15.0 WTF?!!???

Not predictableNot thread-safe

Page 8: Functional programming principles
Page 9: Functional programming principles

func scaling(point:Point, by factor:Double) -> Point { return Point(x: point.x * factor, y: point.y * factor)}

p = scaling(point: p, by: 5)q = scaling(point : q, by: 3)

print(p.x, p.y) // 5.0 5.0

Page 10: Functional programming principles

Immutability

Pure functionsPartial application/currying

Function composition

Functional dependency injection

Page 11: Functional programming principles

Must not have observable side-effects

Same inputs yield same result

Page 12: Functional programming principles

// Pure : concat two strings and return// new string

func + (lhs:String, rhs:String) -> String

// Impure : advances to the next element // and return it

class Generator { func next() -> Element}

Page 13: Functional programming principles

Pure functions are easy to reason about

Reasoning about code that might not be inpure :

customer.set(name:newName)var name = customer.getName()

// Is customeer being changed ?

let newCustomer = set(customer:customer,newName :name) Customer being changed

let name = self.getName(for customer:newCustomer)

Page 14: Functional programming principles
Page 15: Functional programming principles

More practical benefits of pure functions :

• Cacheable (memoization)• same answer every time

• No order dependency• I can evaluate them in every order I like

• Parallelizable

Page 16: Functional programming principles

Immutability

Pure functions

Partial application/CurryingFunction composition

Functional dependency injection

Page 17: Functional programming principles

func setUserPWD(id:String, pwd:String, dbConnection:Connection) -> Result {

let statement = dbConnection.prepareStatememt(for: pwd, id:id) let result = statement.execute() return result}

Page 18: Functional programming principles

main()

level1

level3

level4

level5

needs connection

Page 19: Functional programming principles

func setUserPWD(id:String, pwd:String) -> (Connection -> Result) {

return { connection in let statement = connection.prepareStatememt(for: pwd, id:id) let result = statement.execute() return result }}

let applyConnection = setUserPWD(id:userID, pwd:userPwd)

/// in some place:

let connection = DataManager.connectionlet result = applyConnection(connection)

Let’s apply currying :

Page 20: Functional programming principles
Page 21: Functional programming principles

Partial application :

// getLine : (Double,UIColor, LineStyle) -> Linefunc getLine(width:Double, color:UIColor, style :LineStyle) -> Line

thinSolidLine : (UIColor) -> Linelet thinSolidLine = { color in getLine(width:1.0, color:color, style : .solid)}

Page 22: Functional programming principles

Immutability

Pure functions

Partial application/Currying

Function compositionFunctional dependency injection

Page 23: Functional programming principles

Applying filter to image (functional wrapper around an existing, object-oriented API)

Core Image APIKey class : CIFilter

Example of using :

let parameters = [ kCIInputImageKey: image]

let filter = CIFilter(name: "CIGaussianBlur", withInputParameters: parameters)let outputImage = filter.outputImage()

Page 24: Functional programming principles

FP approach :

typealias Filter = CIImage -> CIImage

func blur(radius: Double) -> Filter { return { image in let parameters = [ kCIInputRadiusKey: radius, kCIInputImageKey: image ] let filter = CIFilter(name: "CIGaussianBlur", withInputParameters: parameters let outputImage = filter.outputImage return outputImage }}

blur filter :

basic type :

Page 25: Functional programming principles

typealias Filter = CIImage -> CIImage

// blur filterfunc blur(radius: Double) -> Filter { … }

// vignette filterfunc vignette(intensity: NSNumber,radius:Double) -> Filter { return { image in let parameters = [ kCIInputRadiusKey : radius, kCIInputIntensityKey: intensity, kCIInputImageKey: image ] let filter = CIFilter(name: "CIVignette", withInputParameters: parameters) let outputImage = filter.outputImage return outputImage }}

Page 26: Functional programming principles

let blurRadius = 5.0let intensity = 3.0let vignetteRadius = 4.0

let image = CIImage(contentsOfURL: url)let blurredImage = blur(blurRadius)(image)let result = vignette(intensity:intensity, radius:vignetteRadius)(blurredImage)

Let’s do something more ..

Page 27: Functional programming principles
Page 28: Functional programming principles

// f(x) and g(x)// composeFilters => f(g(x))

func composeFilters(filter1: Filter, _ filter2: Filter) -> Filter { return { image in filter2(filter1(image)) }}

let myNewFilter = composeFilters(blur(blurRadius), vignette(intensity:intensity,

radius:vignetteRadius))let result = myNewFilter(image)

Page 29: Functional programming principles

And more ..

let myNewFilter = blur(blurRadius) >>> vignette(intensity:intensity, radius:vignetteRadius)let result = myFilter(image)

infix operator >>> { associativity left }

func >>> (filter1: Filter, filter2: Filter) -> Filter { return { image in filter2(filter1(image)) }}

Page 30: Functional programming principles

Immutability

Pure functions

Partial application/Currying

Function composition

Functional dependency injection

Page 31: Functional programming principles

Task : - update user

profile - send notification

Page 32: Functional programming principles

Problem : - Breaked Interface Segregation Principle

(Unneeded interface methods)

class UserProfileUpdateService { let dbService : IDBService let emailService : IEmailService init(dbService:IDBService, emailService:IEmailService) { self.dbService = dbService self.emailService = emailService } func updateProfile(user:User,someInfo:Info) {

let currentEmail = self.dbService.getEmail(user.id) self.dbService.updateProfile(user.id, user.name, someInfo)

emailService.sendEmailNotification(to : currentEmail, with: someInfo)...

}}

Page 33: Functional programming principles

typealias UpdateProfile : (UserID, UserName, Info) -> ()typealias NotifyUser : (Email,Info) -> ()typealias GetEmail : (UserID) -> (Email)

class UserProfileUpdateService { func updateProfile(user:User, someInfo:Info, getEmail : GetEmail updateProfile: UpdateProfile, notify : NotifyUser) { let currentEmail = getEmail(user.id) updateProfile(user.id, user.name, info) notify(currentEmail, someInfo)

... }}// In method call :

let dbService = IDBService()let emailService = IEmailService()userUpdateService.updateProfile(user:someUser, info : someInfo, getEmail: dbService.getEmail, updateProfile : dbService.updateProfile, notify: emailService.sendEmailNotification)

Page 34: Functional programming principles
Page 35: Functional programming principles

Useful links :

http://fsharpforfunandprofit.com

https://www.lektorium.tv/course/22779

http://functionaltalks.org