2010-08-09 27 views
5

tôi đã có thể tìm thấy:Lisp là một DSL nội bộ của Ruby?

a) thông dịch Lisp viết Ruby (ví dụ, một DSL bên ngoài)

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

b) Prolog như một Ruby DSL

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

c) Thảo luận về Ruby "as" a Lisp

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

Nhưng thật lạ lùng, tôi thực sự không thể tìm thấy một triển khai nội bộ -Internal của Lisp, giống như cái cho Prolog. Tôi chỉ không đủ Googly, hoặc có ai chưa đăng một suy nghĩ như vậy?

Hoặc có thể bạn không thể thực hiện điều này trong Ruby?

+2

Điều Prolog trông giống 'phác thảo' hơn, không phải là triển khai thực tế. Tại sao bạn muốn sử dụng Lisp trong Ruby? Ruby có lẽ là một trong những ngôn ngữ tồi tệ nhất để thực hiện các ngôn ngữ khác. Có những trường hợp Ruby chậm hơn hàng trăm lần so với một Lisp điển hình: http://shootout.alioth.debian.org/u32/benchmark.php?test=all&lang = yarv & lang2 = sbcl - bây giờ hãy tưởng tượng sự chậm chạp của Lisp đang chạy trên đầu trang của Ruby. Lisp cũng không phải là DSL, nhưng là một gia đình của các ngôn ngữ lập trình hoàn toàn chung. –

+0

Điều này sẽ khác với "DSL bên ngoài" như thế nào? "Prolog as a Ruby DSL" thay đổi cú pháp của Prolog một chút để làm việc trong Ruby. "Trình thông dịch Lisp viết bằng Ruby" cũng cho phép bạn viết Lisp bằng Ruby với cú pháp hơi khác, ví dụ: '[]' thay vì '()' và ': lambda' thay vì' lambda'. Nhiều hơn những gì bạn muốn? – Ken

+0

Điều này hoàn toàn là một bài tập học tập. Tôi thấy Lisp hấp dẫn như một ngôn ngữ, nhưng rất khó đọc. Tôi biết nó có thể thực hiện Lisp bên trong Lisp (tôi đã làm 20 năm trước!). Có lẽ nó sẽ tương tự dễ dàng để thực hiện Lisp trong Ruby, chỉ với cú pháp đơn giản hơn nhiều - điều này sẽ giúp tôi dễ dàng hiểu được những gì đang diễn ra. –

Trả lời

2

Dưới đây là mã nguồn Ruby cho người phiên dịch Lisp từ trang 13 của cuốn cẩm nang Lisp lập trình viên:

# 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 

Vì vậy, giả sử bạn đã có mã Lisp sau:

(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))))) 

Bạn có thể hiển thị điều này trong DSL là:

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}" 

(Nguồn gốc cho thông dịch viên và ví dụ can be found here.)

Cập nhật: Chỉ cần nhận ra bạn đã đề cập giải pháp này trong câu hỏi của bạn.

Các vấn đề liên quan