-
-
Save nhatlee/7d36a3d39465f76a00a5bd9410942f44 to your computer and use it in GitHub Desktop.
A horrendous example of custom pattern matching in Swift
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
// Playground - noun: a place where people can play | |
import Cocoa | |
enum Wildcard : NilLiteralConvertible { | |
case Single | |
case FromBeginning | |
case ToEnd | |
case Range(Int) | |
case Literal(Int) | |
init(nilLiteral: ()) { | |
self = .Single | |
} | |
} | |
prefix operator * {} | |
prefix func *(value: Int) -> Wildcard { | |
return Wildcard.Literal(value) | |
} | |
prefix operator <~ { } | |
prefix func <~(value: Wildcard) -> Wildcard { | |
return Wildcard.FromBeginning | |
} | |
postfix operator ~> { } | |
postfix func ~>(value: Wildcard) -> Wildcard { | |
return Wildcard.ToEnd | |
} | |
func ~=(pattern: [Wildcard], value: [Int]) -> Bool { | |
var ctr = 0 | |
for currentPattern in pattern { | |
if ctr < 0 || ctr >= value.count { return false } | |
let currentValue = value[ctr] | |
let currentWildcard = currentPattern | |
switch currentWildcard { | |
case .Single: ctr++ | |
case .FromBeginning where ctr == 0: | |
ctr = (value.count - pattern.count + 1) | |
case .FromBeginning: return false | |
case .ToEnd: return true | |
case .Range(let r): ctr += r | |
case .Literal(let v): | |
if v != currentValue { return false } | |
else { ctr++ } | |
} | |
} | |
return true | |
} | |
// Basic version | |
let myArray = [1, 2, 4, 3] | |
switch myArray { | |
case [.FromBeginning, .Literal(0), .Literal(0), .Literal(0)]: | |
"last three elements are 0" | |
case [Wildcard.Literal(4), Wildcard.ToEnd]: | |
"first element is 4, everything else doesn't matter" | |
case [Wildcard.Single, Wildcard.Literal(2), Wildcard.Single, Wildcard.Literal(4)]: | |
"4 elements; second element is 2, fourth element is 4" | |
case [Wildcard.Range(2), Wildcard.Literal(3), Wildcard.Single]: | |
"third element (out of 4) is 3" | |
case [Wildcard.Range(3), Wildcard.Literal(3)]: | |
"fourth element (out of 4) is 3" | |
default: | |
"catchall" | |
} | |
// ADVANCED VERSION: custom operator abuse | |
let anotherArray = [2, 10 ,0, 0, 0] | |
anotherArray.count | |
switch anotherArray { | |
case [<~nil, *0, *0, *0]: | |
"last three elements are 0, everything else doesn't matter" | |
case [*4, nil~>]: | |
"first element is 4, everything else doesn't matter" | |
case [nil, *2, nil, *2]: | |
"4 elements; second element is 2, fourth element is 4" | |
case [nil, nil, *3, nil]: | |
"third element (out of 4) is 3" | |
case [nil, nil, nil, *3]: | |
"fourth element (out of 4) is 3" | |
default: | |
"catchall" | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment