funcitonal swift conference: the functional way

Post on 06-Jul-2015

4.280 Views

Category:

Software

0 Downloads

Preview:

Click to see full reader

DESCRIPTION

Talk about Functional Swift presented at the Functional Swift Conference http://2014.funswiftconf.com/

TRANSCRIPT

THE FUNCTIONAL WAY

@NATASHATHEROBOT

"functional programming is a programming paradigm... that treats

computation as the evaluation of mathematical functions and avoids changing-state and mutable data."

Wikipedia

"A mathematical function is a function that when you give it the same

argument, it will give you the same result" - Edx FP101x

▸ computation as the evaluation of mathematical functions▸ avoid changing state▸ avoid mutable data

NO SIDE EFFECTS

let numbers = Array(1...10)var total = 0

func addNumbers() { for number in numbers { total += number }}

addNumbers()total // 55

addNumbers()total // 110

addNumbers()total // 165

let myNumbers = Array(1...10)var total = addNumbers(myNumbers)

func addNumbers(numbers: [Int]) -> Int { // can also be written shorthand as // numbers.reduce(0,+) return numbers.reduce(0) { (sum, number) in sum + number }}

total = addNumbers(myNumbers) // 55

total = addNumbers(myNumbers) // 55

total = addNumbers(myNumbers) // 55

import Foundation

class Gift {

let recipient: String let item: String let budget: NSDecimalNumber let status: Status

enum Status: String { case Purchased = "Purchased" case Wrapped = "Wrapped" case Delivered = "Delivered" }

init(recipient: String, item: String, budget: NSDecimalNumber, status: Status) { self.recipient = recipient self.item = item self.budget = budget self.status = status }

}

extension Gift {

func todo() -> String { switch status { case .Purchased: return "Wrap it!" case .Wrapped: return "Mail it!" case .Delivered: return "Relax and drink some eggnog :)" } }

}

extension Gift {

func todo(fromStatus status: Status) -> String { switch status { case .Purchased: return "Wrap it!" case .Wrapped: return "Mail it!" case .Delivered: return "Relax and drink some eggnog :)" } }

}

class GiftTests: XCTestCase {

func testTodo_Purchased() { let gift = Gift( recipient: "My Cousin Julie, item: "GoldieBlox", budget: NSDecimalNumber(double: 20.00), status: .Purchased)

XCTAssertEqual(gift.todo(), "Wrap it!") }

func testTodo_Wrapped() { let gift = Gift( recipient: "My Cousin Julie", item: "GoldieBlox", budget: NSDecimalNumber(double: 20.00), status: .Wrapped)

XCTAssertEqual(gift.todo(), "Mail it!") }

func testTodo_Delivered() { let gift = Gift( recipient: "My Cousin Julie", item: "GoldieBlox", budget: NSDecimalNumber(double: 20.00), status: .Delivered)

XCTAssertEqual(gift.todo(), "Relax and drink some eggnog :)") }

}

import XCTest

class GiftTests: XCTestCase {

let gift = Gift( recipient: "My Cousin Tommy", item: "Choo Choo Train", budget: NSDecimalNumber(double: 20.00), status: .Purchased)

func testTodo_Purchased() { XCTAssertEqual(gift.todo(fromStatus: .Purchased), "Wrap it!") }

func testTodo_Wrapped() { XCTAssertEqual(gift.todo(fromStatus: .Wrapped), "Mail it!") }

func testTodo_Delivered() { XCTAssertEqual(gift.todo(fromStatus: .Delivered), "Relax and drink some eggnog :)") }

}

import XCTest

class GiftTests: XCTestCase {

func testTodo_Purchased() { XCTAssertEqual(Gift.todo(fromStatus: .Purchased), "Wrap it!") }

func testTodo_Wrapped() { XCTAssertEqual(Gift.todo(fromStatus: .Wrapped), "Mail it!") }

func testTodo_Delivered() { XCTAssertEqual(Gift.todo(fromStatus: .Delivered), "Relax and drink some eggnog :)") }

}

VALUE TYPES

"Almost all types in Swift are value types, including arrays, dictionaries, numbers, booleans, tuples, and enums. Classes are the exception rather than

the rule." - Functional Swift Book

NSError *err = nil;CGFloat result = [MYArithmetic divide:2.5 by:3.0 error:&err];

if (err) { NSLog(@"%@", err)} else { [MYArithmetic doSomethingWithResult:result]}

@nomothetis

enum Result { case Success(AnyObject) case Failure(NSError)}

@nomothetis

let result = MYArithmetic.divide(2.5, by:3)

switch result {case Success(let quotient): doSomethingWithResult(quotient)case Failure(let error): handleError(error)}

@nomothetis

http://nomothetis.svbtle.com/error-handling-in-swift

CURRYING

func add(x: Int, y: Int) -> Int { return x + y}

add(2, 3) // 5

func add(x: Int) -> Int -> Int { return { y in return x + y }}

let partialAdd = add(2)// let addFunc: (Int -> Int)

let sum = partialAdd(3)// 5

let arr = [1,2,3]let incrementBy2 = arr.map(partialAdd)// [3,4,5]

add(6)(4)// 10

func add(#x: Int)(y: Int) -> Int { return x + y}

add(x: 2)(y: 3)// 5

struct Logger { /// Level of log message to aid in the filtering of logs enum Level: Int, Printable { /// Messages intended only for debug mode case Debug = 3

/// Messages intended to warn of potential errors case Warn = 2

/// Critical error messages case Error = 1

/// Log level to turn off all logging case None = 0

var description: String { switch(self) { case .Debug: return "Debug" case .Warn: return "Warning" case .Error: return "Error" case .None: return "" } } }}

@drewag

extension Logger {

/// What is the max level to be logged /// /// Any logs under the given log level will be ignored static var logLevel: Level = .Warn

/// Log a message to the console static func log (#level: Level) (name: String) (message: String) -> String { if level.rawValue <= Logger.logLevel.rawValue { return "\(level.description): \(name) - \(message)" }

return "" }}

@drewag

Logger.log(level: .Debug)(name: "MyFunction")(message: "Is this being called?")// Debug: MyFunction - Is this being called?

extension Logger {

/// Logger for debug messages static var debug = Logger.log(level: .Debug) // static var debug: (name: String) -> (message: String) -> String

/// Logger for warnings static var warn = Logger.log(level: .Warn)

/// Logger for errors static var error = Logger.log(level: .Error)

}

@drewag

Logger.logLevel = .Debug

func myFunctionToDebug() { var x = 5 // do something to x Logger.debug(name: "myFunctionToDebug")(message: "x: \(x)")}

myFunctionToDebug()// Prints: "Debug: myFunctionToDebug - x: 10"

@drewag

func myFunctionToDebug() { var x = 5 var y = 3

// do something to x // do something to y

let debugMyFunction = Logger.debug(name: "myFunctionToDebug")

debugMyFunction(message: "x: \(x)") debugMyFunction(message: "y: \(y)")}

myFunctionToDebug()// Prints: "Debug: myFunctionToDebug - x: 10"// Prints: "Debug: myFunctionToDebug - y: 13"

http://drewag.me/posts/practical-use-for-curried-functions-in-swift

TYPE-DRIVEN DESIGN

func credits(account: Account) -> Int { // ask data source for account credits return credits}

@FunctionalSwift

typealias Credits = Int

func credits(account: Account) -> Credits { // ask data source for amount of credits return amount}

@FunctionalSwift

"One important lesson I've learned is that designing the right types for your

problem is a great way to help the compiler debug your program." -

@wouterswierstra

struct Credits { let amount: Int }

func credits(account: Account) -> Credits { // ask data source for amount of credits return Credits(amount: amount)}

@FunctionalSwift

let myCredits = credits(myAccount)myCredits + 1 // ERROR// Cannot invoke '+' with an argument of type// '(Credit, IntegerLiteralConvertable)'

http://www.objc.io/snippets/8.html

http://www.swiftcast.tv/articles/the-design-of-types

RESOURCES▸ Functional Swift Book

▸ Edx FP101x▸ Functional Snippets

▸ An Introduction to Haskell - Skills Matter▸ swiftnews.curated.co

QUESTIONS?@NATASHATHEROBOT

top related