Save 37% off PRO during our Black Friday Sale! »

Parser Combinators

9f33218af7ae5c04e102fcc3076f2f5c?s=47 yhkaplan
December 03, 2019

Parser Combinators

9f33218af7ae5c04e102fcc3076f2f5c?s=128

yhkaplan

December 03, 2019
Tweet

Transcript

  1. Parser Combinators 1

  2. Self Intro » Name: Joshua Kaplan » Interests: ! λ

    " » Company: GMO Pepabo » Service: minne 2
  3. What are Parser Combinators? 3

  4. » Higher-order function that takes multiple parsers and /combines/ them

    into a new parser » CS theory » Parsec, Haskell 4
  5. In Swift struct Parser<A> { let run: (inout Substring) throws

    -> A } 5
  6. Characteristics » Monadic » Composable » Generic » Immutable 6

  7. Use let int = Parser<Int> { input in let num

    = input.prefix(while: { $0.isNumber }) guard let number = Int(num) else { throw ParserError.IntError.notANumber(num) } input.removeFirst(num.count) return number } 7
  8. func removingLiteral(_ string: String) -> Parser<Void> { return Parser<Void> {

    input in guard input.hasPrefix(string) else { throw ParserError.StringError.literalNotFound(string[...]) } input.removeFirst(string.count) } } 8
  9. Higher order functions » map » flatMap (bind, >>=) »

    zip 9
  10. struct Coordinate { let x, y: Int } let str

    = "1,2" let coordinateParser = zip( int, removingLiteral(","), int ).map { x, _, y in Coordinate(x: x, y: y) } let (coordinate, _) = try coordinateParser.run(str[...]) ▿ Coordinate - x: 1 - y: 2 10
  11. func substring(while predicate: @escaping (Character) -> Bool) -> Parser<Substring> {

    return Parser<Substring> { input in let p = input.prefix(while: predicate) input.removeFirst(p.count) return p } } 11
  12. Let's make another parser! struct Person { let name: String;

    let age: Int } let str = "name: John, age: 90" 12
  13. Name and age parsers let nameParser = zip( removingLiteral("name: "),

    substring(while: { $0.isLetter }) ).map { _, name in return String(name) } let ageParser = zip( removingLiteral("age: "), int ).map { _, age in return age } 13
  14. Person parser let personParser = zip( nameParser, removingLiteral(", "), ageParser

    ).map { name, _, age in return Person(name: name, age: age) } let (person, _) = try personParser.run(str[...]) ▿ Person - name: "John" - age: 90 14
  15. Comparison » By hand » Scanner 15

  16. Why and when? 16

  17. References » https://github.com/pointfreeco/episode-code- samples/tree/master/0064-parser-combinators-pt3 » https://talk.objc.io/episodes/S01E13-parsing- techniques » https://github.com/johnpatrickmorgan/Sparse »

    https://github.com/davedufresne/SwiftParsec » https://github.com/thoughtbot/Argo » https://github.com/tryswift/TryParsec 17