Super combinators
-
Upload
cocoaheads-france -
Category
Software
-
view
228 -
download
0
Transcript of Super combinators
SUPERCOMBINATORS A "SWIFTY" PARSER COMBINATOR
FRAMEWORK
SWIFTY
Use term with cautionStill being defined
Should mean "familiar"Can mean baggage !
WHY?
Why do this presentation?Why parser combinators?
Why SuperCombinators?
STRINGS
Two potential intended users of a string
1. !2. "
SNIPS
A lot of work on taking text for humans"Show me walking directions home"
Transform into something for machineschmod +x query.txt
ONE APPROACH
Context-free grammar
Assign semantic function to nonterminals
This is not easy to express cleanly in Swift
ONE SOLUTION
Define the semantic function as a String
Transform into a closure
More advanced ExpressibleByStringLiteral
PARSER COMBINATORS
Conceptually: typealias Parser<Value, Collection> = (Collection) -> (Value, Collection)?
Made to be composable
Unlike familiar Cocoa devices
EXISTING SOLUTIONS
A number of frameworks available already
All had downsides▸ Too many custom operators
▸ Memory leaks▸ Swift 2.2
EXISTING SOLUTIONS
Demo/teaching tool
Not for production
CLONE
First we cloned an existing solution
Migration ❤
Became intimately familiar with every line
REIMPLEMENT
What could be made better?▸ String-specific▸ Declarative API
▸ Memory-safe recursion
Other goodies
STRING
String can also be a "substring"let substring: String = text.substring(from: substringIndex)
Completely opaque
Captures text
Cheap to get substring with full String API
SWIFT TYPE CONVEYS SEMANTICS
Collection takes this to an extreme
Helps compiler and programmer
Pattern AND Parser<Value>
Pattern just traverses String
Parser extracts Value
Makes composition implicit while intuitive
OPERATORS
Distinction in types allows for simplification
Just || and & for almost all composition
mirrored by explicit .or(_:) and .and(_:) instance methods
EXTENSIONS
Distinction in types allows for useful extensionsExpressibleByStringLiteral
Swift 3.1:extension Parser where Value == String {}
RECURSIVE PARSERS
Reference cycles
Usually avoidable
Not always obvious how
RECURSIVE PARSERS
Use additional object with unowned reference back
lazily generate parsing function
take Parser -> Parser
EXAMPLElet digits = Pattern.characters(in: .decimalDigits)let int = digits.stringParser.map { Int($0)! }
let sum = Parser<Int>.recursive { sum in return (int & "+" & sum).map(+) || int}
print(sum.parse("1+2+3")!)// prints 6
THANK YOU!
github.com/snipsco/SuperCombinators
Sasha Lopoukhine
github.com/superlopuh@superlopuh