Ở khu vực nào thì macro của LISP tốt hơn khả năng của Ruby trong việc tạo ra DSL


21

Một trong những điều làm cho Ruby tỏa sáng là khả năng tạo Ngôn ngữ cụ thể miền tốt hơn, như

Mặc dù người ta có thể sao chép các thư viện này trong LISP thông qua macro, tôi nghĩ việc triển khai của Ruby thanh lịch hơn. Tuy nhiên, tôi nghĩ rằng có những trường hợp mà macro của LISP có thể tốt hơn Ruby, mặc dù tôi không thể nghĩ ra.

Vậy, ở khu vực nào thì macro của LISP tốt hơn "khả năng" của Ruby để tạo DSL, nếu có?

cập nhật

Tôi đã hỏi điều này bởi vì các ngôn ngữ lập trình hiện đại đang tiếp cận điểm kỳ dị LISP , như

  • C có bộ tiền xử lý mở rộng macro , mặc dù rất nguyên thủy và dễ bị lỗi
  • C # có các thuộc tính, mặc dù đây là chỉ đọc, được hiển thị thông qua sự phản chiếu
  • Python đã thêm trang trí, có thể sửa đổi hành vi của hàm (và lớp cho phiên bản 3.0), mặc dù cảm thấy khá hạn chế.
  • Ruby TMTOWTDI tạo ra DSL thanh lịch, nếu được chăm sóc, nhưng theo cách của Ruby.

Tôi đã tự hỏi nếu macro của LISP chỉ áp dụng cho các trường hợp đặc biệt và các tính năng ngôn ngữ lập trình khác có đủ mạnh để nâng cao tính trừu tượng để đáp ứng những thách thức hiện nay trong phát triển phần mềm.


4
Tôi không chắc tại sao có phiếu bầu chặt chẽ về điều này. Tôi mặc dù đây là loại câu hỏi chúng tôi muốn ? Thú vị, kích thích tư duy và phạm vi được xác định khá tốt.
Tim Post

Hãy thử triển khai một cái gì đó như thế này trong Ruby: meta-alternative.net/pfront.pdf
SK-logic

@Tim Post: Một vấn đề là đây thực sự không phải là một câu hỏi dễ trả lời trừ khi bạn biết rõ cả Lisp và Ruby thông thường. Một cái khác là các tài liệu tham khảo khá thờ ơ với các ngôn ngữ khác, điều này có thể gây khó chịu cho những người theo chủ nghĩa thuần túy: không có ngôn ngữ nào gọi là C / C ++ và phần quan trọng của C ++ là hệ thống mẫu và đề xuất rằng hệ thống macro của Common Lisp chỉ áp dụng cho các trường hợp đặc biệt. Về cơ bản, đó là một câu hỏi hay, nhưng nó được viết rất tệ và rất khó trả lời.
David Thornley

@David Thornley, tôi đã cập nhật bài đăng, đặc biệt là trên C \ C ++ và nhấn mạnh vào C. Đối với Lisp thông thường, tôi cảm thấy rằng vì các ngôn ngữ lập trình khác có tính trừu tượng cao hơn, nên tính năng macro là dành cho trường hợp đặc biệt. Tôi đã đăng câu hỏi, hy vọng rằng những người khác sẽ cho tôi thấy rằng macro của CL không dành cho trường hợp đặc biệt vẫn là một tính năng mạnh mẽ.
OnesimusUnbound

@OnesimusUnbound: Tôi thực sự sẽ đưa các mẫu của C ++ vào danh sách các ví dụ ngôn ngữ của bạn, vì chúng ít nhất có khả năng về mặt lý thuyết cho bất kỳ tính toán nào mà hệ thống macro Lisp có thể làm. Theo như macro của Lisp, hãy nắm giữ một số mã Lisp thông thường tốt (có rất nhiều mã Lisp F / OS ngoài đó) và tìm kiếm "defmacro" (bạn có thể muốn thực hiện tìm kiếm không phân biệt chữ hoa chữ thường). Có lẽ bạn sẽ tìm thấy rất nhiều trong số họ. Hãy xem xét rằng các macro khó hơn các chức năng để viết và hiểu đúng và bạn sẽ nhận ra rằng chúng phải hữu ích.
David Thornley

Câu trả lời:


23

Đọc trên Lisp và sau đó quyết định cho chính mình.

Tóm tắt của tôi là Ruby tốt hơn trong việc cung cấp cú pháp thuận tiện. Nhưng Lisp chiến thắng, nương tay, với khả năng tạo ra sự trừu tượng mới, và sau đó là sự trừu tượng hóa lớp về sự trừu tượng hóa. Nhưng bạn cần nhìn thấy Lisp trong thực tế để hiểu điểm đó. Do đó cuốn sách đề nghị.


1
"Let Over Lambda" bao gồm nhiều mặt bằng tương tự. Cũng nên đọc.
John R. Strohm

But Lisp wins, hands down, at the ability to create new abstractions, and then to layer abstraction on abstraction.Bây giờ tôi biết tại sao. . .
OnesimusUnbound

Nó không phải là một vấn đề lớn để cung cấp bất kỳ loại cú pháp trên đầu Lisp. Trong thực tế, dễ dàng hơn nhiều so với Ruby, nhờ các macro đọc.
SK-logic

1
@ SK-logic: Đúng. Tuy nhiên, Lispers tránh xa các macro của người đọc bởi vì một khi bạn đi xuống tuyến đường đó, nó không còn cảm giác như một Lisp nữa. Trong thực tế, một số biến thể của Lisp, chẳng hạn như Clojure, macro dành cho người đọc dành cho nhà thiết kế ngôn ngữ.
btilly

14

Các cơ sở của Ruby cho tác giả DSL không thay đổi bản chất của ngôn ngữ. Các phương tiện siêu lập trình của Ruby vốn đã gắn liền với cú pháp và ngữ nghĩa của Ruby, và bất cứ điều gì bạn viết phải được đưa vào mô hình đối tượng của Ruby.

Trái ngược với Lisp (và Scheme, có các cơ sở vĩ mô khác nhau ), nơi các macro hoạt động trên chính chương trình trừu tượng. Bởi vì chương trình Lisp một giá trị Lisp, macro là một hàm ánh xạ một cú pháp cơ bản tùy ý sang một cú pháp khác.

Thực tế, Ruby DSL vẫn có cảm giác như Ruby, nhưng DSL của Lisp không phải cảm thấy giống Lisp.


6
+1: LOOP không cảm thấy rất Lispy, như một ví dụ về DSL.
Frank Shearar

2

Các DSL của Ruby hoàn toàn không phải là DSL và tôi hoàn toàn ghét sử dụng chúng vì tài liệu của chúng hoàn toàn nói dối về cách chúng thực sự hoạt động. Hãy lấy ActiveRecord làm ví dụ. Nó cho phép bạn "khai báo" các liên kết giữa các Mô hình:

class Foo < ActiveRecord::Base
    has_one :bar
    has_one :baz
end

Nhưng tính từ chối của "DSL" này (giống như tính khử của classchính cú pháp của Ruby ) là một lời nói dối khủng khiếp có thể bị lộ bởi bất kỳ ai hiểu cách Ruby "DSL" thực sự hoạt động:

class Foo < ActiveRecord::Base
    [:bar,:baz,:qux,:quux].each do |table|
        has_one table if i_feel_like_it?(table)
    end
    puts "Just for shits and giggles, and to show"
    puts "just how fucked up Ruby really is, we're gonna ask you"
    puts "which SQL table you want the Foo model to have an"
    puts "association with.\n"
    puts "Type the name of a table here: "
    has_one gets.chomp.to_sym
end

(Chỉ cần thử làm bất cứ điều gì gần với điều đó trong cơ thể của một defclasshình thức Lisp !)

Ngay khi bạn có mã như trên trong cơ sở mã của mình, mọi nhà phát triển trong dự án phải hiểu đầy đủ cách Ruby DSL thực sự hoạt động (không chỉ là ảo ảnh mà họ tạo ra) trước khi họ có thể duy trì mã. Các tài liệu có sẵn sẽ hoàn toàn vô dụng, bởi vì chúng chỉ ghi lại cách sử dụng thành ngữ , giúp duy trì ảo giác khai báo.

RSpec thậm chí còn tồi tệ hơn so với ở trên, bởi vì nó có các trường hợp cạnh kỳ quái đòi hỏi kỹ thuật đảo ngược rộng rãi để gỡ lỗi. (Tôi đã dành cả ngày cố gắng tìm ra lý do tại sao một trong các trường hợp thử nghiệm của tôi đã bị bỏ qua. Hóa ra là RSpec thực hiện tất cả các trường hợp thử nghiệm có bối cảnh sau khi trường hợp thử nghiệm không có bối cảnh, không phụ thuộc vào thứ tự mà chúng xuất hiện trong nguồn , bởi vì contextphương thức đặt khối của bạn trong một cấu trúc dữ liệu khác với cách thông thường.)

Lisp DSL được triển khai bởi các macro, là các trình biên dịch nhỏ. Các DSL bạn có thể tạo theo cách này không chỉ là lạm dụng cú pháp hiện có của Lisp. Chúng là những ngôn ngữ nhỏ thực sự có thể được viết hoàn toàn liền mạch, bởi vì chúng có thể có ngữ pháp riêng. Ví dụ, LOOPmacro của Lisp mạnh hơn nhiều so với eachphương pháp của Ruby .

(Tôi biết bạn đã chấp nhận câu trả lời, nhưng không phải ai đọc nó cũng sẽ muốn đọc toàn bộ On Lisp .)

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.