1

Given a Parser type as following:

public struct Parser<Result> {
  internal let parse: (String) -> (Result, String)?

  public func run(_ string: String) -> (Result, String)? {
    guard let (result, remainder) = parse(string) else { return nil }
    return (result, remainder)
  }

  public func map<T>(_ transform: @escaping (Result) -> T )
    -> Parser<T> {
      return Parser<T> { input in
        guard let (result, remainder) = self.run(input) else { return nil }
        return (transform(result), remainder)
      }
  }

  public func followed<A>(by other: Parser<A>) -> Parser<(Result, A)> {
    return Parser<(Result, A)> {  input in
      guard let (result, remainder) = self.run(input) else { return nil }
      guard let (resultA, remainderA) = other.run(remainder) else { return nil }
      return ((result, resultA), remainderA)
    }
  }
}

First implementation as following:

infix operator >>> : FunctionCompositionPrecedence
public func >>> <A, B> (lhs: Parser<A>, rhs: Parser<B>) 
  -> Parser<(A,B)> {
  return lhs.followed(by: rhs)
}

Second implementation as following:

infix operator >>> : FunctionCompositionPrecedence
extension Parser {
  public static func >>> <A, B> (lhs: Parser<A>, rhs: Parser<B>) 
    -> Parser<(A,B)> {
    return lhs.followed(by: rhs)
  }
}

Reclaim the question as what is the difference between the first implementation and the second one.

Moreover, when I use the first implementation, and compile the following code, the compiler reported an error as "'map' produces 'Parser', not the expected contextual result type 'Parser'"

extension Parser {
  public static func apply <A, B> (_ lhs: Parser<(A)->B>, _ rhs: Parser<A>) -> Parser<B> {
    return (lhs >>> rhs).map{(arg) -> B in let (f, x) = arg; return f(x)}
  }
}

However, after I use the second implementation, everything goes fine. I am so confused about the essential nuances between them.

Keith
  • 111
  • 1
  • 6
  • I presumed "*when I use the first implementation, and compile the following code, the compiler reported an error*" was a typo and that you're actually talking about the second implementation, right? The first compiles just fine for me along with `apply(_:_:)`. – Hamish Nov 30 '17 at 15:00

1 Answers1

2

With

infix operator >>> : FunctionCompositionPrecedence
extension Parser {
  public static func >>> <A, B> (lhs: Parser<A>, rhs: Parser<B>) 
    -> Parser<(A,B)> {
    return lhs.followed(by: rhs)
  }
}

You've provided no way for the compiler to infer the generic placeholder Result on calling the operator (really I think the compiler should error here rather than on usage). Remember that static methods on generic types are called on specialisations of those types; the placeholders must be satisfied (as they're accessible at static scope).

So to directly answer

what is the difference between the first implementation and the second one.

The main difference is that as a static member, you have the additional generic placeholder Result that needs to be satisfied; as a top-level function, you don't have that.

So, if you want to keep >>> as a static method, you'll want to use the Result placeholder in the signature of your operator implementation such that the compiler can infer its type on usage, for example:

infix operator >>> : FunctionCompositionPrecedence
extension Parser {

  public static func >>> <B> (
    lhs: Parser, rhs: Parser<B> 
  ) -> Parser<(Result, B)> {
      return lhs.followed(by: rhs)
  }
}

Now Result can be inferred from the type of the argument passed as the lhs of the operator (Parser is syntactic sugar for Parser<Result> in this context).

Note you'll face a similar problem with

extension Parser {
  public static func apply <A, B> (_ lhs: Parser<(A)->B>, _ rhs: Parser<A>) -> Parser<B> {
    return (lhs >>> rhs).map{(arg) -> B in let (f, x) = arg; return f(x)}
  }
}

in that you'll need to explicitly satisfy the Result placeholder when calling; although the type used to satisfy it won't actually be used by the method.

Better would be to use the Result placeholder in the signature to allow the compiler to infer it at the call-site:

extension Parser {

  public static func apply<Arg>(
    _ lhs: Parser<(Arg) -> Result>, _ rhs: Parser<Arg>
  ) -> Parser<Result> {

    return (lhs >>> rhs).map { arg -> Result in
      let (f, x) = arg
      return f(x)
    }
  }
}

// ...

let p = Parser<(String) -> String> { input in ({ $0 + input }, "hello") }
let p1 = Parser { ($0, "") }

let p2 = Parser.apply(p, p1)
print(p2.run(" world") as Any) // Optional(("hello world", ""))

Or, better still, as an instance method:

extension Parser {

  public func apply<A, B>(with rhs: Parser<A>) -> Parser<B>
    where Result == (A) -> B {

    return (self >>> rhs).map { arg -> B in
      let (f, x) = arg
      return f(x)
    }
  }
}

// ...

let p = Parser<(String) -> String> { input in ({ $0 + input }, "hello") }
let p1 = Parser { ($0, "") }

let p2 = p.apply(with: p1)
print(p2.run(" world") as Any) // Optional(("hello world", ""))
Hamish
  • 78,605
  • 19
  • 187
  • 280
  • Wow. It truly makes sense. I was so silly that I hadn't thought about that. Thank you very much. I will take an experiment on your reasoning. Thanks again. – Keith Dec 01 '17 at 06:55