Last active
June 8, 2017 05:16
-
-
Save rob-brown/a757b0bcff8f4a3a3797fdca01eb4938 to your computer and use it in GitHub Desktop.
Use Church Encoding to create objects using only functions
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//: 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