2010-08-09 66 views
5

我已经能够找到:书面红宝石(即外部DSL)Lisp作为内部Ruby DSL?

http://onestepback.org/index.cgi/Tech/Ruby/LispInRuby.red

B)序言作为Ruby DSL

http://www.kdedevelopers.org/node/2369

一)Lisp的口译

c)讨论Ruby“as”Lisp

http://www.randomhacks.net/articles/2005/12/03/why-ruby-is-an-acceptable-lisp

但奇怪的是,我实际上找不到Lisp的内部实现,就像Prolog的实现一样。我只是不够格力,还是没有人发布过这样的想法?

或者它可能是一个不能做到这一点在Ruby?

+2

Prolog的东西看起来更像'草图',而不是实际的实现。你为什么要在Ruby中使用Lisp? Ruby可能是实现其他语言的最差语言之一。有些情况下Ruby比典型的Lisp慢百倍:http://shootout.alioth.debian.org/u32/benchmark.php?test=all&lang = yarv&lang2 = sbcl - 现在想象一下运行在Ruby之上的Lisp的缓慢。 Lisp也不是DSL,而是一系列完全一般的编程语言。 – 2010-08-09 21:05:45

+0

这与“外部DSL”有何不同? “Prolog作为Ruby DSL”稍微改变了Prolog的语法以在Ruby中工作。 “在Ruby中编写的Lisp解释器”还允许你在Ruby中编写具有稍微不同语法的Lisp,例如'[]'而不是'()'和':lambda'而不是'lambda'。你还想要什么? – Ken 2010-08-09 21:10:15

+0

这纯粹是作为一种学习练习。我发现Lisp作为一种语言引人入胜,但是很痛苦。我知道可以在Lisp里面实现Lisp(我在20多年前就已经完成了!)。推测在Ruby中实现Lisp同样很容易,只需要简单得多的语法 - 这会让我更容易理解发生了什么。 – 2010-08-09 21:38:42

回答

2

下面是Lisp的程序员手册第13页的Lisp解释了Ruby代码:

# Kernel Extensions to support Lisp 
class Object 
    def lisp_string 
    to_s 
    end 
end 

class NilClass 
    def lisp_string 
    "nil" 
    end 
end 

class Array 
    # Convert an Array into an S-expression (i.e. linked list). 
    # Subarrays are converted as well. 
    def sexp 
    result = nil 
    reverse.each do |item| 
     item = item.sexp if item.respond_to?(:sexp) 
     result = cons(item, result) 
    end 
    result 
    end 
end 

# The Basic Lisp Cons cell data structures. Cons cells consist of a 
# head and a tail. 
class Cons 
    attr_reader :head, :tail 

    def initialize(head, tail) 
    @head, @tail = head, tail 
    end 

    def ==(other) 
    return false unless other.class == Cons 
    return true if self.object_id == other.object_id 
    return car(self) == car(other) && cdr(self) == cdr(other) 
    end 

    # Convert the lisp expression to a string. 
    def lisp_string 
    e = self 
    result = "(" 
    while e 
     if e.class != Cons 
     result << ". " << e.lisp_string 
     e = nil 
     else 
     result << car(e).lisp_string 
     e = cdr(e) 
     result << " " if e 
     end 
    end 
    result << ")" 
    result 
    end 
end 

    # Lisp Primitive Functions. 

    # It is an atom if it is not a cons cell. 
    def atom?(a) 
    a.class != Cons 
    end 

    # Get the head of a list. 
    def car(e) 
    e.head 
    end 

    # Get the tail of a list. 
    def cdr(e) 
    e.tail 
    end 

    # Construct a new list from a head and a tail. 
    def cons(h,t) 
    Cons.new(h,t) 
    end 

    # Here is the guts of the Lisp interpreter. Apply and eval work 
    # together to interpret the S-expression. These definitions are taken 
    # directly from page 13 of the Lisp 1.5 Programmer's Manual. 

    def apply(fn, x, a) 
    if atom?(fn) 
     case fn 
     when :car then caar(x) 
     when :cdr then cdar(x) 
     when :cons then cons(car(x), cadr(x)) 
     when :atom then atom?(car(x)) 
     when :eq then car(x) == cadr(x) 
     else 
     apply(eval(fn,a), x, a) 
     end 
    elsif car(fn) == :lambda 
     eval(caddr(fn), pairlis(cadr(fn), x, a)) 
    elsif car(fn) == :label 
     apply(caddr(fn), x, cons(cons(cadr(fn), caddr(fn)), a)) 
    end 
    end 

    def eval(e,a) 
    if atom?(e) 
     cdr(assoc(e,a)) 
    elsif atom?(car(e)) 
     if car(e) == :quote 
     cadr(e) 
     elsif car(e) == :cond 
     evcon(cdr(e),a) 
     else 
     apply(car(e), evlis(cdr(e), a), a) 
     end 
    else 
     apply(car(e), evlis(cdr(e), a), a) 
    end 
    end 

    # And now some utility functions used by apply and eval. These are 
    # also given in the Lisp 1.5 Programmer's Manual. 

    def evcon(c,a) 
    if eval(caar(c), a) 
     eval(cadar(c), a) 
    else 
     evcon(cdr(c), a) 
    end 
    end 

    def evlis(m, a) 
    if m.nil? 
     nil 
    else 
     cons(eval(car(m),a), evlis(cdr(m), a)) 
    end 
    end 

    def assoc(a, e) 
    if e.nil? 
     fail "#{a.inspect} not bound" 
    elsif a == caar(e) 
     car(e) 
    else 
     assoc(a, cdr(e)) 
    end 
    end 

    def pairlis(vars, vals, a) 
    while vars && vals 
     a = cons(cons(car(vars), car(vals)), a) 
     vars = cdr(vars) 
     vals = cdr(vals) 
    end 
    a 
    end 

    # Handy lisp utility functions built on car and cdr. 

    def caar(e) 
    car(car(e)) 
    end 

    def cadr(e) 
    car(cdr(e)) 
    end 

    def caddr(e) 
    car(cdr(cdr(e))) 
    end 

    def cdar(e) 
    cdr(car(e)) 
    end 

    def cadar(e) 
    car(cdr(car(e))) 
    end 

所以我们说你有以下Lisp代码:

(defun reverse (list) 
    (rev-shift list nil)) 

(defun rev-shift (list result) 
    (cond ((null list) result) 
    (t (rev-shift (cdr list) (cons (car list) result))))) 

你可以在DSL中呈现为:

require 'lisp' 

    # Create an environment where the reverse, rev_shift and null 
    # functions are bound to an appropriate identifier. 

    env = [ 
    cons(:rev_shift, 
     [:lambda, [:list, :result], 
     [:cond, 
      [[:null, :list], :result], 
      [:t, [:rev_shift, [:cdr, :list], 
       [:cons, [:car, :list], :result]]]]].sexp), 
    cons(:reverse, 
     [:lambda, [:list], [:rev_shift, :list, nil]].sexp), 
    cons(:null, [:lambda, [:e], [:eq, :e, nil]].sexp), 
    cons(:t, true), 
    cons(nil, nil) 
    ].sexp 

    # Evaluate an S-Expression and print the result 

    exp = [:reverse, [:quote, [:a, :b, :c, :d, :e]]].sexp 

    puts "EVAL: #{exp.lisp_string}" 
    puts " => #{eval(exp,env).lisp_string}" 

(解释器和示例的原始源can be found here。)

更新:刚才意识到你在你的问题中提到了这个解决方案。