【问题标题】:Recursive aliases in CeylonCeylon 中的递归别名
【发布时间】:2015-02-18 17:25:42
【问题描述】:

我是 Ceylon 的新手,目前正在探索如何将一些用 TypeScript(主要是 JavaScript)编写的现有软件移植到 Ceylon,以便它可以在 JavaScript 引擎和 JVM 上运行。

有人知道如何在 Ceylon 中编写类似 Java 的代码吗:

public class Engine { ... } // Some given class definition

public interface Cont extends Callable1<Cont,Engine> {}

其中Callable1&lt;Y,X&gt; 是 Ceylon 的 Callable&lt;Y,[X]&gt; 的 Java 等价物。

这个想法是Cont 的实例,比如名为c,将是一个返回另一个Contnull 的函数。

在 Java 中,使用它的代码如下所示:

// Somewhere
public static void exec(Cont c, Engine e) {
  while (c != null) c = c.call(e);
}

(这本质上是一个蹦床,每个被调用的函数都返回延续,或者在计算完成时返回null。)

另外,在锡兰我想将函数作为 Cont 的实例传递。


阅读回复后,我提出了以下解决方案,它使用正确的结果类型(Cont? 而不是Anything)和null-testing(用于性能):

shared interface Cont { shared formal Cont? call(Engine e); }

// A wrapper class for an actual continuation function
class ContWrap(Cont?(Engine) fun) satisfies Cont {
    shared actual Cont? call(Engine e) => fun(e);
}

shared Cont wrap(Cont?(Engine) fun) {
    return ContWrap(fun);
}

// Somewhere
shared void exec(variable Cont? cont) {
    while (exists cc = cont) {
        cont = cc.call(this);
    }
}

这适合我,代价是每次都创建一个额外的小对象,并通过 wrap 传递函数。

【问题讨论】:

  • 如果wrap(fun)ContWrap(fun)一样,为什么不直接做后者呢?
  • @gdejohn,这纯粹是出于设计原因:ContWrap 是实现特定行为的辅助内部类,因此用户不应该意识到它(当然也不应该编写依赖于它)。另一方面,函数wrap 是API 的一部分(即,它是一个工厂函数)。

标签: ceylon


【解决方案1】:

Callable 的自定义实现是 discussed,但目前还不可能。不过,你不需要那个。

shared class Engine() {
    // ...
}

shared interface Continuation {
    shared formal Continuation? call(Engine engine);
}

shared void execute(variable Continuation? continuation, Engine engine) {
    while ((continuation = continuation?.call(engine)) exists) {}
}

object continuation satisfies Continuation {
    call(Engine engine) => null;
}

// usage
execute(continuation, Engine());

// usage in 1.2 with inline object expression
execute(object satisfies Continuation { call(Engine engine) => null; }, Engine());

由于Continuation 不(不能)满足Callable,你不能只传入一个函数。但是在即将发布的版本中(1.2,现在可以通过 GitHub 获得),你至少可以使用inline object expressions

请注意,这不是惯用的 Ceylon,只是从您的 Java 相当直接的翻译。

【讨论】:

  • 谢谢@gdejohn!这可能是一个很好的解决方案,至少在 1.2 中(否则我想必须为每个函数对象编写一个类,这是不切实际的)。但是,一个很大的优势是它使用快速的null 检查而不是(我猜要慢得多)is Type 检查。我将等待 1.2 发布,并提供更新的 IDE 支持。
【解决方案2】:

这似乎可以编译,但看起来很可怕:

class Engine() {}

Anything(Engine) foo(Engine e) {
    return foo;
}

// Somewhere
variable Anything(Engine)? f = foo;
while (is Anything(Engine)(Engine) f2=f) {
    f = f2(e);
}

【讨论】:

  • 非常感谢您的建议!我唯一担心的是is-testing 可能会比null-testing 产生很大的开销,因为前者需要查看运行时类型信息并遵循类层次结构,而后者只是一个整数比较。跨度>
  • (继续)这就是我选择null-testing 变体的原因。顺便说一句,我从理论的角度理解类型系统的复杂性,但是例如在 Typescript 中,可以简单地指定 interface Cont { (e: Engine): Cont; } 所谓的调用签名接口并在那里传递函数。所以这可以很容易地在 Java 和 Typescript 中完成并进行类型检查,但不幸的是在 Ceylon 中并不那么容易。
  • @user241495,this 你在说什么?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-05-11
  • 1970-01-01
  • 1970-01-01
  • 2012-11-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多