แมโครของ LISP นั้นดีกว่า“ ความสามารถ” ของรูบี้ในการสร้าง DSL


21

หนึ่งในสิ่งที่ทำให้ Ruby shine คือความสามารถในการสร้าง Domain Specific Languages ​​ที่ดีขึ้นเช่น

แม้ว่าเราสามารถทำซ้ำไลบรารี่เหล่านี้ใน LISP ผ่านมาโครได้ แต่ฉันคิดว่าการติดตั้งของรูบี้นั้นสง่างามกว่า อย่างไรก็ตามฉันคิดว่ามีบางกรณีที่แมโครของ LISP นั้นสามารถทำได้ดีกว่ารูบี้แม้ว่าฉันจะไม่สามารถคิดได้

ดังนั้นมาโครของ LISP ในพื้นที่ใดที่ดีกว่า "ความสามารถ" ของรูบี้ในการสร้าง DSL ถ้ามี?

ปรับปรุง

ฉันถามสิ่งนี้เพราะภาษาการเขียนโปรแกรมที่ทันสมัยกำลังเข้าใกล้ LISP เอกพจน์เช่น

  • C มีตัวประมวลผลก่อนการขยายตัวของแมโครแม้ว่าจะเป็นแบบดั้งเดิมและมีแนวโน้มที่จะเกิดข้อผิดพลาด
  • C # มีคุณสมบัติแม้ว่าจะเป็นแบบอ่านอย่างเดียวซึ่งเปิดเผยผ่านการสะท้อนกลับ
  • Python ได้เพิ่มมัณฑนากรที่สามารถปรับเปลี่ยนพฤติกรรมของฟังก์ชั่น (และคลาสสำหรับ v 3.0) แต่รู้สึกค่อนข้าง จำกัด
  • Ruby TMTOWTDI ที่ทำให้ DSL สง่างามหากใช้งานอย่างระมัดระวัง แต่เป็น Ruby

ฉันสงสัยว่าแมโครของ LISP นั้นใช้ได้กับกรณีพิเศษเท่านั้นและคุณสมบัติภาษาการเขียนโปรแกรมอื่นนั้นมีประสิทธิภาพเพียงพอที่จะยกระดับสิ่งที่เป็นนามธรรมเพื่อตอบสนองความท้าทายในการพัฒนาซอฟต์แวร์ในปัจจุบัน


4
ฉันไม่แน่ใจว่าทำไมจึงมีคะแนนเสียงใกล้เคียงนี้ ฉันคิดว่านี่เป็นคำถามที่เราต้องการหรือไม่ น่าสนใจกระตุ้นความคิดและกำหนดขอบเขตค่อนข้างดี
Tim Post

ลองใช้สิ่งนี้ใน Ruby: meta-alternative.net/pfront.pdf
SK-logic

@Tim Post: ปัญหาหนึ่งคือว่านี่ไม่ใช่คำถามง่าย ๆ ที่จะตอบเว้นแต่ว่าคุณรู้ทั้ง Common LISP และ Ruby อย่างดี อีกประการหนึ่งคือการอ้างอิงที่ไม่ฉลาดพอที่จะใช้ภาษาอื่นซึ่งอาจรบกวนคนที่ไม่ชำนาญ: ไม่มีภาษาที่เรียกว่า C / C ++ และส่วนสำคัญของ C ++ คือระบบเทมเพลตและข้อเสนอแนะที่ระบบมาโคร Lisp ทั่วไปใช้ได้กับกรณีพิเศษเท่านั้น โดยพื้นฐานแล้วเป็นคำถามที่ดี แต่เขียนได้ไม่ดีและตอบยาก
David Thornley

@ David Thornley ฉันได้อัปเดตโพสต์โดยเฉพาะอย่างยิ่งใน C \ C ++ และให้ความสำคัญกับ C. สำหรับ Common LISP ฉันรู้สึกว่าเนื่องจากภาษาการเขียนโปรแกรมอื่นมีความเป็นนามธรรมที่สูงขึ้นคุณลักษณะแมโครจึงเหมาะสำหรับกรณีพิเศษ ฉันโพสต์คำถามโดยหวังว่าคนอื่นจะแสดงให้ฉันเห็นว่ามาโครของ CL ไม่ได้มีไว้สำหรับกรณีพิเศษยังคงเป็นคุณสมบัติที่ทรงพลัง
OnesimusUnbound

@OnesimusUnbound: ฉันต้องการรวมเทมเพลตของ C ++ ในรายการตัวอย่างภาษาของคุณเนื่องจากอย่างน้อยพวกเขามีความสามารถทางทฤษฎีในการคำนวณใด ๆ ที่ระบบมาโคร Lisp สามารถทำได้ ตราบใดที่มาโครของ Lisp ใช้รหัส Common LISP ที่ดี (มีรหัส FIS / เสียงกระเพื่อมที่นั่นมากมาย) และค้นหา "defmacro" (คุณอาจต้องการค้นหาแบบตัวพิมพ์เล็ก) คุณอาจจะเจอพวกเขามากมาย พิจารณาว่ามาโครนั้นยากกว่าฟังก์ชั่นในการเขียนและทำให้ถูกต้องและคุณจะรู้ว่าต้องมีประโยชน์โดยทั่วไป
David Thornley

คำตอบ:


23

อ่านบนเสียงกระเพื่อมและตัดสินใจด้วยตัวเอง

สรุปของฉันคือทับทิมดีกว่าที่ให้ไวยากรณ์ที่สะดวก แต่ Lisp ชนะลงมือที่ความสามารถในการสร้าง abstractions ใหม่และจากนั้นให้เลเยอร์นามธรรมใน abstraction แต่คุณต้องเห็นเสียงกระเพื่อมในทางปฏิบัติเพื่อทำความเข้าใจจุดนั้น ดังนั้นหนังสือแนะนำ


1
"Let Over Lambda" ครอบคลุมพื้นดินที่คล้ายกันมาก ยังแนะนำให้อ่าน
John R. Strohm

But Lisp wins, hands down, at the ability to create new abstractions, and then to layer abstraction on abstraction.ตอนนี้ฉันรู้ว่าทำไม . .
OnesimusUnbound

มันไม่ใช่เรื่องใหญ่ที่จะให้รูปแบบของไวยากรณ์ใด ๆ บน Lisp อันที่จริงแล้วง่ายกว่าทับทิมมากด้วยขอบคุณมาโครผู้อ่าน
SK-logic

1
@ SK-logic: จริง อย่างไรก็ตาม Lispers นั้นอยู่ห่างจากมาโครของผู้อ่านเพราะเมื่อคุณลงไปในเส้นทางนั้นมันจะไม่รู้สึกเหมือนเสียงกระเพื่อมอีกต่อไป ในความเป็นจริงแล้วตัวแปรบางส่วนของ LISP เช่น Clojure มาโครตัวอ่านสำรองสำหรับผู้ออกแบบภาษา
btilly

14

สิ่งอำนวยความสะดวกของ Ruby สำหรับการเขียน DSL จะไม่เปลี่ยนลักษณะของภาษา สิ่งอำนวยความสะดวก metaprogramming ของ Ruby นั้นเชื่อมโยงกับไวยากรณ์และความหมายของ Ruby โดยปริยาย

ตรงกันข้ามกับ Lisp (และ Scheme ซึ่งสิ่งอำนวยความสะดวกของแมโครแตกต่างกัน ) ซึ่งแมโครทำงานบนโปรแกรมนามธรรมเอง เนื่องจากโปรแกรม Lisp เป็นค่า Lisp แมโครจึงเป็นฟังก์ชันการแมปหนึ่งโดยหลักไวยากรณ์โดยพลการไปยังอีก

อย่างมีประสิทธิภาพ Ruby DSL ยังคงรู้สึกเหมือน Ruby แต่ Lisp DSL นั้นไม่จำเป็นต้องรู้สึกเหมือน Lisp


6
+1: LOOP ไม่รู้สึกว่า Lispy เป็นตัวอย่างของ DSL
Frank Shearar

2

รูดี้ DSL ไม่ได้เป็น DSL เลยและฉันเกลียดที่จะใช้พวกเขาเพราะเอกสารประกอบของพวกเขานั้นอยู่ที่ว่าพวกเขาทำงานอย่างไร ลองใช้ ActiveRecord เป็นตัวอย่าง จะช่วยให้คุณ "ประกาศ" การเชื่อมโยงระหว่างโมเดล:

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

แต่ความไม่ลงรอยกันของ "DSL" นี้ (เช่นความไม่พอใจในclassไวยากรณ์ของรูบี้เอง) เป็นคำโกหกที่น่ากลัวที่ทุกคนที่เข้าใจว่าทับทิม "DSLs" ใช้งานได้จริง:

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

(เพียงลองทำสิ่งใดก็ตามที่อยู่ใกล้กับสิ่งนั้นภายในร่างของเสียงกระเพื่อมdefclass!

ทันทีที่คุณมีรหัสเหมือนข้างต้นใน codebase ของคุณพัฒนาทุกโครงการที่มีการเข้าใจว่าทับทิมมี DSL จริงการทำงาน (ไม่ได้เป็นเพียงภาพลวงตาที่พวกเขาสร้าง) ก่อนที่พวกเขาสามารถรักษารหัส เอกสารที่มีอยู่จะไม่มีประโยชน์อย่างสมบูรณ์เพราะเอกสารเหล่านั้นมีเพียงการใช้สำนวนซึ่งรักษาภาพลวงตาที่เปิดเผย

RSpec ยิ่งเลวร้ายยิ่งกว่าเนื่องจากมีกรณีที่แปลกประหลาดที่ต้องใช้วิศวกรรมย้อนกลับที่ครอบคลุมในการดีบัก (ฉันใช้เวลาทั้งวันพยายามที่จะคิดออกว่าเหตุใดหนึ่งในกรณีทดสอบของฉันถูกข้ามมันกลับกลายเป็นว่า RSpec ดำเนินการกรณีทดสอบทั้งหมดที่มีบริบทหลังจากกรณีทดสอบโดยไม่มีบริบทโดยไม่คำนึงถึงลำดับที่ปรากฏในแหล่งที่มา เนื่องจากcontextวิธีการทำให้บล็อกของคุณอยู่ในโครงสร้างข้อมูลที่แตกต่างจากปกติจะเข้าไป)

Lisp DSLs ถูกใช้งานโดยมาโครซึ่งเป็นคอมไพเลอร์ตัวน้อย DSL ที่คุณสามารถสร้างด้วยวิธีนี้ไม่ได้เป็นการละเมิดไวยากรณ์ที่มีอยู่ของ Lisp เท่านั้น พวกเขาเป็นภาษามินิจริงที่สามารถเขียนได้อย่างไร้รอยต่อเพราะพวกเขามีไวยากรณ์ของตัวเอง ยกตัวอย่างเช่นLOOPมาโครLisp มีพลังมากกว่าeachวิธีของรูบี้

(ฉันรู้ว่าคุณได้รับคำตอบแล้ว แต่ไม่ใช่ทุกคนที่อ่านข้อความนี้จะต้องการอ่านOn Lispทั้งหมด)

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.