"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
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 }
}
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 :)")
}
}
"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
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
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
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
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"
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)'