Skip to content

Instantly share code, notes, and snippets.

@austinzheng
Last active August 1, 2018 07:04
Show Gist options
  • Save austinzheng/0af8aba547b1965d76c1 to your computer and use it in GitHub Desktop.
Save austinzheng/0af8aba547b1965d76c1 to your computer and use it in GitHub Desktop.
A horrendous example of custom pattern matching in Swift
// 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