Last active
May 20, 2016 17:14
-
-
Save callionica/8520e7604860f7980231625a9e981286 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
// 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