【问题标题】:I want to make a Lisp implementation in Java. How many functions do I need to define in Java at a maximum? [closed]我想用 Java 做一个 Lisp 实现。我最多需要在 Java 中定义多少个函数? [关闭]
【发布时间】:2013-11-26 09:22:06
【问题描述】:

根据this 问题的答案,只要您在语言本身中实现eval 函数,在Lisp 中实现任何东西只需要五个实际函数。我说的对吗?

我想用 Java 实现一个非常简约的 Lisp,使用尽可能小和简单的解释器使其尽可能小。我可以只用这五个功能吗?它甚至会如何从 Java 中调用eval?我不知道如何解决这个问题。任何人都有这样编写的解释器示例,并且用另一种语言实现了非常小的实现?

【问题讨论】:

  • 当一个真正有效的问题被由于自己的无知而无法理解的人关闭时,这种情况变得太普遍了。 OP 在问什么非常明显,这是一个非常实际和具体的问题。对SO感到羞耻。如果你不明白这个问题 - 走开,好吗?
  • @SK-logic 我同意“不清楚你在问什么”是关闭这个问题的错误理由。然而,第二段是一个问题列表,其中一些问题实在是太宽泛了,并且会吸引列表的答案(例如,“它甚至如何从 Java 调用 eval?”和“任何人都有任何这样编写的解释器示例,带有用另一种语言实现的极少?”)我认为这个问题需要成为一个更具体的编程问题,然后才能真正成为 Stack Overflow 的主题。
  • @JoshuaTaylor,它仍然归结为一个问题(尽管我同意给定的措辞远非完美):“构建简约的 Lisp 实现需要哪些最小的原语集”。
  • @SK-logic 标题有,但问题没有。问题还问,例如,“它怎么会从 Java 调用 eval?”如果答案只列举了原语,那么它不会回答“我的 Lisp 如何从 Java 调用 eval?”如果它只回答“我的 Lisp 如何从 Java 调用 eval?”那么它不会回答“什么是必要的原语?”一种刻薄的方法会专注于“我正确吗?”并回答“是”。我认为不清楚 OP 在问什么,但我认为 OP 在一个问题上问的太多了。
  • @JoshuaTaylor,在简约解释器中调用eval 函数绝对取决于解释原语的选择。不确定是否可以单独设计这些东西(例如,请参阅我的答案)。

标签: java function lisp eval interpreter


【解决方案1】:

您不必在 Java 中实现太多。

即使是 S 表达式解析也可以在 Lisp 中实现,Java 部分只负责读取一些简单的序列化形式。例如,在类似 Forth 的语法中,如 (a (b c)) -> a b c NIL . . NIL . .,其中 . 构成一个 cons 单元格。

Java 运行时应该提供极少的原语集。无需支持完整的 Lisp 语义,在 Lisp 本身中将编译器从“完整”的 Lisp 实现为简化的引导语言会更容易。引导语言可能支持以下原语:

  • FUNCTION,制作一个函数对象,具有给定数量的参数和给定的主体
  • ARG,访问函数的第 n 个参数
  • VAR,访问闭包的第 n 个槽
  • IF原语
  • APPLY原语
  • CONST原语
  • CLOSURE 原语 - 类似于函数对象,但初始化了许多闭包环境槽

在 Java 中实现这样的解释器很容易,上面的所有原语都是通过方法 Run(Environment env) 实现相同的 AstNode 接口的类。

在 Lisp 方面,必须实现一个简单的“编译器”,它将执行 lambda 提升和变量枚举。像letlet* 等,可以实现为简单的宏(Lisp 本身也实现了宏扩展器)。

Java 提供的一组最小的运行时库函数应包含 car、cdr、cons、listp、nullp、符号到字符串和字符串到符号的转换、字符串连接以及对 Java 反射的访问,以实现从Lisp 方面。

当然,这样的解释器效率不会很高 - 例如,您必须通过 Y-combinator 实现递归函数。但是,您只需要它来引导一种语言的下一次迭代,当然也可以在 Lisp 中实现,它将相同的源语言编译成 Java 字节码。

变化是可能的 - 例如,可以实现一个简单的graph reduction 引擎而不是上面的解释器,它更简单,但效率更低。

【讨论】:

    【解决方案2】:

    您需要一个用 Java 编写的 REPL(读取-评估-打印循环),它将读取和解析用户提供的任何 Lisp 行:这就是您的 eval 函数的作用。解析 Lisp s 表达式相当容易:列表的第一项是函数调用,其他元素是应用于该函数的参数。而应用函数只是意味着用给定的属性替换函数的主体,并减少它直到达到公理。例如:

    ((lambda (x y) (cons x (cons y x))) 1 2)
    

    将被评估为

    (cons 1 (cons 2 1))
    

    而且,在这里,您已经达到了只有公理的水平。实际上,公理函数本身不是函数,它们是特殊形式,即由您的 eval 函数直接处理,这意味着它们也必须在 Java 中实现。

    好吧,请注意,只有这 7 个公理的 lisp 解释器将是 very 原始的。您将没有算术运算、没有比较、没有字符串等。所有这些都必须在公理之上实现。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-09-10
      • 2018-11-05
      • 2010-09-27
      • 2013-03-16
      • 1970-01-01
      • 2014-07-07
      • 2012-06-25
      • 1970-01-01
      相关资源
      最近更新 更多