Skip to content

Instantly share code, notes, and snippets.

@rob-brown
Last active June 8, 2017 05:16
Show Gist options
  • Save rob-brown/a757b0bcff8f4a3a3797fdca01eb4938 to your computer and use it in GitHub Desktop.
Save rob-brown/a757b0bcff8f4a3a3797fdca01eb4938 to your computer and use it in GitHub Desktop.
Use Church Encoding to create objects using only functions
//: Playground - noun: a place where people can play
import UIKit
// ----------------------------
// Create the "object".
// Basically it's a dispatch table.
typealias Person = (String) -> Any
var PersonInit: ((String, String) -> Person)!
PersonInit = { (firstName: String, lastName: String) -> Person in
return { method in
switch method {
case "firstName":
return firstName
case "lastName":
return lastName
case "fullName":
return firstName + " " + lastName
case "setFirstName":
return { (newName: String) -> Person in
return PersonInit(newName, lastName)
}
case "setLastName":
return { (newName: String) -> Person in
return PersonInit(firstName, newName)
}
case "setNames":
return { newFirstName in
return { newLastName in
return PersonInit(newFirstName, newLastName)
}
}
case _:
fatalError("Unknown method")
}
}
}
// ----------------------------
// Create the "methods"
let firstName = { (person: Person) -> String in
return person("firstName") as! String
}
let lastName = { (person: Person) -> String in
return person("lastName") as! String
}
let fullName = { (person: Person) -> String in
return person("fullName") as! String
}
let setFirstName = { (person: Person) -> ((String) -> Person) in
return person("setFirstName") as! ((String) -> Person)
}
let setLastName = { (person: Person) -> ((String) -> Person) in
return person("setLastName") as! ((String) -> Person)
}
let setNames = { (person: Person) -> ((String) -> ((String) -> Person)) in
return person("setNames") as! ((String) -> ((String) -> Person))
}
// ----------------------------
// Quick test
let papa = PersonInit("Papa", "Smurf")
fullName(papa) // "Papa Smurf"
let brainy = setFirstName(papa)("Brainy")
fullName(brainy) // "Brainy Smurf"
// ----------------------------
// Add a dot-like operator.
infix operator =>
func => <T>(lhs: Person, rhs: (Person) -> T) -> T {
return rhs(lhs)
}
func => <T, A>(lhs: Person, rhs: (((Person) -> (A) -> T), A)) -> T {
return rhs.0(lhs)(rhs.1)
}
func => <T, A, B>(lhs: Person, rhs: (((Person) -> (A) -> (B) -> T), A, B)) -> T {
return rhs.0(lhs)(rhs.1)(rhs.2)
}
// ----------------------------
// The result
papa=>firstName // "Papa"
papa=>lastName // "Smurf"
papa=>fullName // "Papa Smurf"
let hefty = papa=>(setFirstName, "Hefty")
hefty=>fullName // "Hefty Smurf"
let gargamel = hefty=>(setNames, "Gargamel", "the wizard")
gargamel=>fullName // "Gargamel the wizard"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment