Skip to content

Instantly share code, notes, and snippets.

@callionica
Last active May 20, 2016 17:14
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save callionica/8520e7604860f7980231625a9e981286 to your computer and use it in GitHub Desktop.
Save callionica/8520e7604860f7980231625a9e981286 to your computer and use it in GitHub Desktop.
// This is just some noodling based on Brent's interest in Swift responder chains: http://inessential.com/2016/05/15/a_hypothetical_responder_chain_written_i
// Just showing that responder chain can easily fit with the level of dynamism in Swift today
infix operator >>> { associativity left }
func >>> <In, Middle, Out>(first: In -> Middle, second: Middle -> Out) -> In -> Out {
return { x in second(first(x)) }
}
func >>> <In, Out>(deduce: In.Type, fn: In -> Out) -> In -> Out {
return fn
}
func >>> <In, Out>(fn: In -> Out, deduce: Out.Type) -> In -> Out {
return fn
}
//////////////////////////////////////
protocol IResponder {
var nextResponder : IResponder? { get }
}
// getResponder returns the first responder from which the policy function is able to obtain a valid interface
func getResponder<T>(firstResponder : IResponder, _ policy : (IResponder)-> T?)->T? {
var responder = firstResponder
while (true) {
print("examine")
if let validResponder = policy(responder) {
return validResponder;
}
if responder.nextResponder == nil {
return nil;
}
responder = responder.nextResponder!
}
}
class Responder: IResponder {
var nextResponder: IResponder?
}
//////////////////////////////////////
protocol IDynamic {
var enabled : Bool { get }
}
func isEnabled<In>(input: In)->Bool {
// Responder enabled if it's dynamic and enabled or if it's not dynamic
let dyn = input as? IDynamic
return (dyn != nil && dyn!.enabled) || (dyn == nil)
}
// Create a new function from a test and an existing function
func precheck<In,Out>(check : (In)->Bool, _ policy : (In)-> Out?)->(In)-> Out? {
return { (input)->Out? in
if (!check(input)) {
return nil
}
return policy(input)
}
}
// Given an output type, return a function that optionally casts the input to that Type
// We can use this in places where Swift can deduce the input type
func cast<In,Out>(proto: Out.Type)->(In)->Out? {
return { (input : In) in input as? Out }
}
//////////////////////////////////////
protocol ICopyable {
func copy()
}
class Copyable : Responder, IDynamic, ICopyable {
var enabled: Bool = true;
func copy() {
print("copied")
}
}
class NonCopyable : Responder {
}
let a = Copyable()
let b = NonCopyable();
let c = NonCopyable();
c.nextResponder = b;
b.nextResponder = a;
if let x = getResponder(c, cast(ICopyable.self)) {
x.copy()
} else {
print("surprise")
}
let enabledCopyablePolicy = IResponder.self >>> precheck(isEnabled, cast(ICopyable.self))
if let y = getResponder(c, enabledCopyablePolicy) {
y.copy()
} else {
print("surprise")
}
a.enabled = false;
if let n = getResponder(c, enabledCopyablePolicy) {
n.copy()
} else {
print("correctly disabled")
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment