- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
给定一个解析器类型如下:
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)
}
}
}
第一次实现如下:
infix operator >>> : FunctionCompositionPrecedence
public func >>> <A, B> (lhs: Parser<A>, rhs: Parser<B>)
-> Parser<(A,B)> {
return lhs.followed(by: rhs)
}
第二次实现如下:
infix operator >>> : FunctionCompositionPrecedence
extension Parser {
public static func >>> <A, B> (lhs: Parser<A>, rhs: Parser<B>)
-> Parser<(A,B)> {
return lhs.followed(by: rhs)
}
}
将问题重新定义为第一个实现与第二个实现之间的区别。
另外,当我使用第一个实现,编译如下代码时,编译器报错如下“‘map’产生‘Parser’,而不是预期的上下文结果类型‘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)}
}
}
但是,在我使用第二个实现后,一切正常。我对它们之间的细微差别感到非常困惑。
最佳答案
与
infix operator >>> : FunctionCompositionPrecedence
extension Parser {
public static func >>> <A, B> (lhs: Parser<A>, rhs: Parser<B>)
-> Parser<(A,B)> {
return lhs.followed(by: rhs)
}
}
您没有为编译器提供任何方法来推断通用占位符 Result
在调用运算符时(我真的认为编译器应该在此处出错而不是在使用时出错)。请记住,泛型类型的静态方法是在这些类型的特化 上调用的;必须满足占位符(因为它们可以在静态范围内访问)。
直接回答
what is the difference between the first implementation and the second one.
主要区别在于,作为静态成员,您有额外的通用占位符 Result
需要满足;作为顶级功能,您没有。
所以,如果你想保留 >>>
作为静态方法,您需要使用 Result
运算符实现签名中的占位符,以便编译器可以根据使用情况推断其类型,例如:
infix operator >>> : FunctionCompositionPrecedence
extension Parser {
public static func >>> <B> (
lhs: Parser, rhs: Parser<B>
) -> Parser<(Result, B)> {
return lhs.followed(by: rhs)
}
}
现在Result
可以从作为 lhs
传递的参数类型推断出来运算符的( Parser
在这种情况下是 Parser<Result>
的语法糖)。
注意你会遇到类似的问题
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)}
}
}
因为您需要明确满足 Result
调用时的占位符;尽管用于满足它的类型实际上不会被该方法使用。
更好的方法是使用 Result
签名中的占位符以允许编译器在调用站点推断它:
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", ""))
或者,更好的是,作为实例方法:
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", ""))
关于Swift 4.0 在类型内部实现自定义运算符作为类型方法与在全局范围内实现自定义运算符作为全局函数之间的区别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47571798/
C语言sscanf()函数:从字符串中读取指定格式的数据 头文件: ?
最近,我有一个关于工作预评估的问题,即使查询了每个功能的工作原理,我也不知道如何解决。这是一个伪代码。 下面是一个名为foo()的函数,该函数将被传递一个值并返回一个值。如果将以下值传递给foo函数,
CStr 函数 返回表达式,该表达式已被转换为 String 子类型的 Variant。 CStr(expression) expression 参数是任意有效的表达式。 说明 通常,可以
CSng 函数 返回表达式,该表达式已被转换为 Single 子类型的 Variant。 CSng(expression) expression 参数是任意有效的表达式。 说明 通常,可
CreateObject 函数 创建并返回对 Automation 对象的引用。 CreateObject(servername.typename [, location]) 参数 serv
Cos 函数 返回某个角的余弦值。 Cos(number) number 参数可以是任何将某个角表示为弧度的有效数值表达式。 说明 Cos 函数取某个角并返回直角三角形两边的比值。此比值是
CLng 函数 返回表达式,此表达式已被转换为 Long 子类型的 Variant。 CLng(expression) expression 参数是任意有效的表达式。 说明 通常,您可以使
CInt 函数 返回表达式,此表达式已被转换为 Integer 子类型的 Variant。 CInt(expression) expression 参数是任意有效的表达式。 说明 通常,可
Chr 函数 返回与指定的 ANSI 字符代码相对应的字符。 Chr(charcode) charcode 参数是可以标识字符的数字。 说明 从 0 到 31 的数字表示标准的不可打印的
CDbl 函数 返回表达式,此表达式已被转换为 Double 子类型的 Variant。 CDbl(expression) expression 参数是任意有效的表达式。 说明 通常,您可
CDate 函数 返回表达式,此表达式已被转换为 Date 子类型的 Variant。 CDate(date) date 参数是任意有效的日期表达式。 说明 IsDate 函数用于判断 d
CCur 函数 返回表达式,此表达式已被转换为 Currency 子类型的 Variant。 CCur(expression) expression 参数是任意有效的表达式。 说明 通常,
CByte 函数 返回表达式,此表达式已被转换为 Byte 子类型的 Variant。 CByte(expression) expression 参数是任意有效的表达式。 说明 通常,可以
CBool 函数 返回表达式,此表达式已转换为 Boolean 子类型的 Variant。 CBool(expression) expression 是任意有效的表达式。 说明 如果 ex
Atn 函数 返回数值的反正切值。 Atn(number) number 参数可以是任意有效的数值表达式。 说明 Atn 函数计算直角三角形两个边的比值 (number) 并返回对应角的弧
Asc 函数 返回与字符串的第一个字母对应的 ANSI 字符代码。 Asc(string) string 参数是任意有效的字符串表达式。如果 string 参数未包含字符,则将发生运行时错误。
Array 函数 返回包含数组的 Variant。 Array(arglist) arglist 参数是赋给包含在 Variant 中的数组元素的值的列表(用逗号分隔)。如果没有指定此参数,则
Abs 函数 返回数字的绝对值。 Abs(number) number 参数可以是任意有效的数值表达式。如果 number 包含 Null,则返回 Null;如果是未初始化变量,则返回 0。
FormatPercent 函数 返回表达式,此表达式已被格式化为尾随有 % 符号的百分比(乘以 100 )。 FormatPercent(expression[,NumDigitsAfterD
FormatNumber 函数 返回表达式,此表达式已被格式化为数值。 FormatNumber( expression [,NumDigitsAfterDecimal [,Inc
我是一名优秀的程序员,十分优秀!