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

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

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是否正确?
  • 在哪里可以找到有关Frege编译器源代码中的TListDListDCons的更多信息?是否有文件记录?
  • 关于Frege最佳实践的一个更通用的问题:当您希望Java代码使用Frege值时,从Frege代码中返回Java“标准”对象会更好还是直接从Java中使用Frege类呢?我认为前者比后者更容易编写,但转换开销很小。例如,始终可以通过将TListIterator转换为Frege的Java TList来避免LinkedList
  • 最佳答案

    首先,此wiki page是从Java调用Frege的最终指南。

    它解释了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类型Foo在Java中获得名称TFoo
  • Frege数据构造函数Bar获得名称DBar
  • 检查我们是否有DBar的方法是_Bar。 (请注意,没有显式字段可对构造函数进行编码,因此我们将JVM对象 header 用于无论如何都要对其进行编码的目的)

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

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

    还有另一种可能性是返回一个数组。例如,如您在REPL中所看到的,以下内容
    foo a b c = arrayFromList [a,b,c] :: JArray Int
    

    将获得如下签名:
    final public static int[] foo(...
    

    09-12 03:18