From 8d0febaec821b6b56d3bd216169e0ae3a65de546 Mon Sep 17 00:00:00 2001 From: David Tchepak Date: Mon, 2 Mar 2015 17:57:45 +1100 Subject: [PATCH] map and flatMap - renamed mapParser to map, as it is already scoped to Parser - flatMap --- ParserExerciseTests/ParserExerciseTests.swift | 44 +++++++++++++++++-- 1 file changed, 40 insertions(+), 4 deletions(-) diff --git a/ParserExerciseTests/ParserExerciseTests.swift b/ParserExerciseTests/ParserExerciseTests.swift index 923a66d..30a7343 100644 --- a/ParserExerciseTests/ParserExerciseTests.swift +++ b/ParserExerciseTests/ParserExerciseTests.swift @@ -139,7 +139,7 @@ class CharacterParserTests : XCTestCase { extension Parser { // Return a parser that maps any succeeding result with the given function. // Hint: will require the construction of a `Parser` and pattern matching on the result of `self.parse`. - public func mapParser(f : A -> B) -> Parser { + public func map(f : A -> B) -> Parser { //return TODO() return Parser({ s in switch self.parse(s) { @@ -152,19 +152,55 @@ extension Parser { class MapParserTests : XCTestCase { func testMap() { - let result = character().mapParser(toUpper).parse("abc") + let result = character().map(toUpper).parse("abc") assertEqual(result, succeed("bc", "A")) } func testMapAgain() { - let result = valueParser(10).mapParser({ $0+1 }).parse("abc") + let result = valueParser(10).map({ $0+1 }).parse("abc") assertEqual(result, succeed("abc", 11)) } func testMapWithErrorResult() { - let result = failed().mapParser({ $0 + 1 }).parse("abc") + let result = failed().map({ $0 + 1 }).parse("abc") assertEqual(result, failParse()) } } +extension Parser { + // Return a parser based on this parser (`self`). The new parser should run its input through + // this parser, then: + // + // * if this parser succeeds with a value (type A), put that value into the given function + // then put the remaining input into the resulting parser. + // + // * if this parser fails with an error the returned parser fails with that error. + // + public func flatMap(f : A -> Parser) -> Parser { + //return TODO() + return Parser({ s in + switch self.parse(s) { + case .ErrorResult(let e): return failWithParseError(e) + case .Result(let i, let v): return f(v.value).parse(i) + } + }) + } +} + +public class FlatMapParserTests : XCTestCase { + let parseWhileX : Parser = + character().flatMap({ c in + if c == "x" { return valueParser("!") } // if c=="x", return "!" value + else { return character() } // else skip this character and parse the next one + }) + func testFlatMap() { + let result = parseWhileX.parse("abcd") + assertEqual(result, succeed("cd", "b")) + } + func testFlatMapAgain() { + let result = parseWhileX.parse("xabc") + assertEqual(result, succeed("abc", "!")) + } +} + // END EXERCISES