Last active
April 12, 2018 14:00
-
-
Save vinivendra/d3a308e83acdc100133a to your computer and use it in GitHub Desktop.
This file contains 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
import Foundation | |
// Usage examples at the end of the gist | |
func giveEmotionsToFunction<InputType, OutputType> | |
(_ function: @escaping (InputType) -> OutputType) -> ((InputType) -> OutputType) | |
{ | |
return { input in | |
print(" =) ") | |
let output = function(input) | |
print(" =( ") | |
return output | |
} | |
} | |
func createPerformanceLogDelegate<InputType, OutputType>( | |
_ functionName: String = "", | |
_ function: @escaping ((InputType) -> OutputType)) -> ((InputType) -> OutputType) | |
{ | |
return { argument in | |
let start = DispatchTime.now() | |
let result = function(argument) | |
let end = DispatchTime.now() | |
let nanoTime = end.uptimeNanoseconds - start.uptimeNanoseconds | |
let timeInterval = Double(nanoTime) / 1_000_000_000 // Could overflow | |
print("\(functionName)(\(argument)) = \(result)\n\(timeInterval) seconds to evaluate.") | |
return result | |
} | |
} | |
func createLogDelegate<InputType, OutputType>( | |
_ functionName: String = "", | |
_ function: @escaping ((InputType) -> OutputType)) -> ((InputType) -> OutputType) | |
{ | |
return { argument in | |
let result = function(argument) | |
print("\(functionName)(\(argument)) = \(result)") | |
return result | |
} | |
} | |
func createRecursiveLogDelegate<InputType, OutputType>( | |
_ functionName: String = "", | |
_ function: @escaping ((((InputType) -> OutputType), InputType) -> OutputType)) | |
-> ((InputType) -> OutputType) | |
{ | |
var delegateFunction: ((InputType) -> OutputType)! | |
var indentation = -1 | |
delegateFunction = { argument in | |
indentation += 1 | |
let result = function(delegateFunction, argument) | |
for _ in 0..<indentation { | |
print(" ", terminator:"") | |
} | |
print("\(functionName)(\(argument)) = \(result)") | |
indentation -= 1 | |
return result | |
} | |
return delegateFunction | |
} | |
func fibonacci(_ recursive: ((Int) -> Int), n: Int) -> Int { | |
if n <= 2 { | |
return 1 | |
} else { | |
return recursive(n - 1) + recursive(n - 2) | |
} | |
} | |
func createMemoizeDelegate<InputType: Hashable, OutputType>( | |
_ function: @escaping ((((InputType) -> OutputType), InputType) -> OutputType)) | |
-> ((InputType) -> OutputType) | |
{ | |
var table = [InputType : OutputType]() | |
var delegateFunction: ((InputType) -> OutputType)! | |
delegateFunction = { argument in | |
if let result = table[argument] { | |
return result | |
} else { | |
let result = function(delegateFunction, argument) | |
table[argument] = result | |
return result | |
} | |
} | |
return delegateFunction | |
} | |
func factorial(_ n: Int) -> Int { | |
return n <= 1 ? 1 : factorial(n-1) * n | |
} | |
func createTestDelegate<InputType, OutputType: Equatable>( | |
_ function: @escaping (InputType) -> OutputType) -> ((InputType, OutputType) -> ()) | |
{ | |
return { input, output in | |
assert(function(input) == output) | |
} | |
} | |
func createAsyncDelegate<InputType, OutputType>( | |
queue: qos_class_t = QOS_CLASS_BACKGROUND, | |
callback: @escaping (OutputType) -> () = { _ in }, | |
function: @escaping ((InputType) -> OutputType)) -> ((InputType) -> ()) | |
{ | |
return { argument in | |
DispatchQueue.global(qos: .userInitiated).async { | |
let result = function(argument) | |
DispatchQueue.main.async { | |
callback(result) | |
} | |
} | |
} | |
} | |
///////////////////////////////////////////////////////////////////////////// | |
///////////////////////////////////////////////////////////////////////////// | |
///////////////////////////////////////////////////////////////////////////// | |
///////////////////////////////////////////////////////////////////////////// | |
// Examples | |
///////////////////////////////////////////////////////////////////////////// | |
let importantFunction = { print("Hello!") } | |
let importantFunctionWithEmotions: () -> () = { | |
print(" =) ") | |
importantFunction() | |
print(" =( ") | |
} | |
importantFunctionWithEmotions() // Smiles, does its work, then frowns | |
print() | |
///////////////////////////////////////////////////////////////////////////// | |
let foo = { print($0) } | |
let fooWithEmotions = giveEmotionsToFunction(foo) | |
fooWithEmotions("Hello!") | |
print() | |
///////////////////////////////////////////////////////////////////////////// | |
func addOne(_ n: Int) -> Int { | |
return n + 1 | |
} | |
let addOneAndLog = createPerformanceLogDelegate("addOne", addOne) | |
let three = addOneAndLog(2) | |
// Prints: | |
// addOne(2) = 3 | |
// 2.57e-07 seconds to evaluate. | |
print() | |
///////////////////////////////////////////////////////////////////////////// | |
let logFibonacci = createRecursiveLogDelegate("fibonacci", fibonacci) | |
let hundredAndTwenty = logFibonacci(5) | |
// Prints: | |
// fibonacci(2) = 1 | |
// fibonacci(1) = 1 | |
// fibonacci(3) = 2 | |
// fibonacci(2) = 1 | |
// fibonacci(4) = 3 | |
// fibonacci(2) = 1 | |
// fibonacci(1) = 1 | |
// fibonacci(3) = 2 | |
//fibonacci(5) = 5 | |
print() | |
///////////////////////////////////////////////////////////////////////////// | |
let memoizedFibonacci = createMemoizeDelegate(fibonacci) | |
let bigNumber = memoizedFibonacci(50) // Runs in O(n) instead of O(holy crap!) | |
// or O(1) if called in order | |
print(bigNumber) | |
// This probably won't return before the program ends so we won't see the result :( | |
let asyncFactorial = createAsyncDelegate( | |
callback: { print("Async factorial returned! Result is \($0)") }, | |
function: factorial) | |
// Calculates in a separate thread, prints the result in the main thread | |
asyncFactorial(20) | |
print() | |
///////////////////////////////////////////////////////////////////////////// | |
let testFactorial = createTestDelegate(factorial) | |
// Tests each input against its expected output | |
testFactorial(1, 1) | |
testFactorial(2, 2) | |
testFactorial(3, 6) | |
testFactorial(4, 24) | |
testFactorial(5, 120) | |
///////////////////////////////////////////////////////////////////////////// | |
let logFib = createLogDelegate("f", fibonacci) | |
let allFibonacci = createMemoizeDelegate(logFib) | |
_ = allFibonacci(40) // Prints every fibonacci number from 1 to 40 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment