问题
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.
回答1:
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", ""))
来源:https://stackoverflow.com/questions/47571798/swift-4-0-difference-between-implementing-custom-operator-inside-a-type-as-a-typ