5

我想了解 Frege List 的工作原理以及如何从 Java 中使用它。当我下载 Frege 编译器代码时,我发现很难从 Frege 代码中理解 Frege 列表是什么。

做一些测试,我发现 Frege List 是TListJava 中类的一个实例,它有一个特殊的方法,称为_Cons(),它返回一个DCons对象。DCons正如预期的那样,是一对,其中该对的第一个元素对应于列表的头部,而第二个元素是尾部,因此是另一个TList. 在_Cons()空列表上调用时,返回值为 null。因此,要在 Frege 上实现一个 Java 迭代器TList,可以这样写:

public class TListIterator implements Iterator<Object> {
    DCons elem;
    public TListIterator(TList list) {
      this.elem = list._Cons();
    }

    @Override
    public boolean hasNext() {
      return this.elem != null;
    }

    @Override
    public Object next() {
      final Object head = Delayed.<Object>forced( this.elem.mem1 );
      this.elem = this.elem.mem2.<TList>forced()._Cons();
      return head;
    }

    @Override
    public void remove() {
      throw new RuntimeException( "Remove is not implemented" );
    }
}

我的问题是:

  • 我的解释TList正确吗?
  • 是否TListIterator正确?
  • 我在哪里可以找到更多关于什么TList和在 Frege 编译器源代码中的DList信息?DCons他们有记录吗?
  • 关于 Frege 最佳实践的一个更通用的问题:当您希望 Java 代码使用 Frege 值时,从 Frege 代码返回 Java“标准”对象更好还是直接使用 Java 中的 Frege 类更好?我的观点是前者比后者更容易编写,但转换开销很小。例如,TListIterator总是可以通过将Frege转换TList为 Java来避免 a。LinkedList
4

1 回答 1

6

首先,从 Java 调用 Frege 的终极指南是这个wiki 页面

它解释了 frege 数据声明是如何出现在 Java 代码中的。

列表唯一的特别之处是在任何地方都没有明确的 Frege 声明,但我们可以假设它看起来像:

data List a = List | Cons a (List a)

请注意,List等号后面的标识符是空列表的构造函数,通常称为Nil. 调用它的原因List(与类型相同)是因为将 frege 名称转换为有效 java 名称的例程转换[]为 List。在 Frege 源代码中,我们也使用[]类型名称和构造函数名称。

下面是上面对应的Java代码的大纲:

public interface TList extends frege.runtime.Value, frege.runtime.Lazy {
  public TList.DCons _Cons() ;
  public TList.DList _List() ;
  final public static class DCons extends frege.runtime.Algebraic implements TList {
    private DCons(final java.lang.Object arg$1, final frege.runtime.Lazy arg$2) {
      mem1 = arg$1; mem2 = arg$2;
    }
    final public static TList mk(final java.lang.Object arg$1, final frege.runtime.Lazy arg$2) {
      return new DCons(arg$1, arg$2);
    }
    final public DCons _Cons() { return this; }
    final public TList.DList _List() { return null; }
    final public java.lang.Object mem1 ;
    final public frege.runtime.Lazy mem2 ;
  }
  final public static class DList extends frege.runtime.Algebraic implements TList {
    private DList() {}
    final public static TList mk() { return it; }
    final public static DList it = new DList();
    final public DList _List() { return this;}
    final public TList.DCons _Cons() { return null; }
  }
}

如您所见,整体类型是 interface TList。对列表唯一能做的就是检查变体,为此我们有_List() 和_Cons() 方法。正如您正确观察到的, _Cons()null为空列表返回,并TLIst.DCons为非空列表返回一个实例。从那里你可以提取头部(mem1)和尾部(mem2)。

据我所知,您的列表迭代器应该可以正常工作。

观察简单的编码以避免Java中的重复名称:

  • Frege 类型在 Java 中Foo获得名称。TFoo
  • Frege 数据构造函数Bar获取名称DBar
  • 检查我们是否有 a 的方法DBar_Bar。(请注意,没有对构造函数进行编码的显式字段,这样我们就使用 JVM 对象头来达到我们的目的,无论如何都要对其进行编码)

当然,乍一看,这个名字有点神秘。但它也不完全适用于普通用户。事实上,我认为从 Java 调用 Frege 对任何人来说都不会有趣。但现在我的想法不同了,我们正在设计一种方法,使在 Frege 中实现 Java 接口成为可能(看起来这也可以满足您的目的)。

对于你的最后一个问题,我会说这取决于。如果您可以只返回 int 或 double 或 string,那肯定是最好的。如果这不起作用并且您需要一个列表,那么您使用自定义迭代器的方法是可取的,恕我直言。另一种方法是创建一个 Java List,但这不是纯粹的,因为 List 必须在 Frege 中声明为可变的。此外,您会通过有效地复制列表来浪费空间。

另一种可能性是返回一个数组。例如,正如您在 REPL 中看到的,以下

foo a b c = arrayFromList [a,b,c] :: JArray Int

会得到一个签名,如:

final public static int[] foo(...
于 2014-05-14T00:35:31.537 回答