ปัญหา
พิจารณาปัญหาการออกแบบต่อไปนี้ใน Haskell ฉันมีความเรียบง่าย, EDSL สัญลักษณ์ที่ฉันต้องการที่จะแสดงตัวแปรและการแสดงออกทั่วไป (มีหลายชื่อหลายตัวแปร) x^2 * y + 2*z + 1เช่น นอกจากนี้ผมต้องการที่จะแสดงสมสัญลักษณ์บางกว่าการแสดงออกการพูดx^2 + 1 = 1เช่นเดียวกับคำนิยามx := 2*y - 2เช่น
เป้าหมายคือ:
- มีประเภทที่แยกต่างหากสำหรับตัวแปรและนิพจน์ทั่วไป - ฟังก์ชันบางอย่างอาจนำไปใช้กับตัวแปรและไม่ใช่นิพจน์ที่ซับซ้อน ตัวอย่างเช่นตัวดำเนินการคำนิยาม
:=อาจเป็นประเภท(:=) :: Variable -> Expression -> Definitionและไม่ควรส่งผ่านนิพจน์ที่ซับซ้อนเป็นพารามิเตอร์ด้านซ้ายมือ (แม้ว่ามันจะเป็นไปได้ที่จะส่งตัวแปรเป็นพารามิเตอร์ด้านขวาโดยไม่ต้องมีการแคสต์อย่างชัดเจน ) . - มีตัวอย่างของนิพจน์
Numเพื่อให้สามารถส่งเสริมตัวอักษรจำนวนเต็มเป็นนิพจน์และใช้สัญลักษณ์ที่สะดวกสำหรับการดำเนินการเกี่ยวกับพีชคณิตทั่วไปเช่นการบวกหรือการคูณโดยไม่ต้องแนะนำตัวดำเนินการ wrapper เสริม
ในคำอื่น ๆ ผมอยากจะมีนัยและคงประเภทหล่อ (บังคับ) ของตัวแปรที่จะแสดงออก ตอนนี้ฉันรู้แล้วว่าไม่มีการปลดเปลื้องประเภทใน Haskell อย่างไรก็ตามแนวคิดการเขียนโปรแกรมเชิงวัตถุบางอย่าง (การสืบทอดง่าย ๆ ในกรณีนี้) สามารถแสดงได้ในระบบประเภทของ Haskell ไม่ว่าจะมีหรือไม่มีนามสกุลภาษา ฉันจะตอบสนองประเด็นทั้งสองข้างต้นได้อย่างไรในขณะที่ยังคงไวยากรณ์ที่มีน้ำหนักเบาไว้ เป็นไปได้ไหม
อภิปรายผล
เป็นที่ชัดเจนว่าปัญหาหลักที่นี่คือการNumจำกัด ประเภทของเช่น
(+) :: Num a => a -> a -> a
โดยหลักการแล้วเป็นไปได้ที่จะเขียนชนิดข้อมูลพีชคณิต (ทั่วไป) เดียวสำหรับทั้งตัวแปรและนิพจน์ จากนั้นหนึ่งสามารถเขียน:=ในลักษณะที่แสดงออกทางด้านซ้ายมือมีการแบ่งแยกและยอมรับเฉพาะตัวสร้างตัวแปรที่มีข้อผิดพลาดรันไทม์เป็นอย่างอื่น อย่างไรก็ตามนั่นไม่ใช่วิธีการทำความสะอาดแบบคงที่ (เช่นเวลารวบรวม) ...
ตัวอย่าง
นึกคิดฉันต้องการบรรลุไวยากรณ์ที่มีน้ำหนักเบาเช่น
computation = do
x <- variable
t <- variable
t |:=| x^2 - 1
solve (t |==| 0)
โดยเฉพาะฉันต้องการห้ามใช้สัญกรณ์อย่าง
t + 1 |:=| x^2 - 1นั้นเนื่องจาก:=ควรให้คำจำกัดความของตัวแปรและไม่ใช่การแสดงออกทางซ้ายมือทั้งหมด
FromVarพิมพ์ดีดจะช่วยได้อย่างไร ฉันต้องการที่จะหลีกเลี่ยงการปลดเปลื้องอย่างชัดเจนในขณะที่เก็บตัวอย่างของExpr Numฉันแก้ไขคำถามโดยเพิ่มตัวอย่างของสัญกรณ์ที่ฉันต้องการบรรลุ
class FromVar eพร้อมเมธอดfromVar :: Variable -> eและระบุอินสแตนซ์ให้ExpressionและVariableจากนั้นให้ตัวแปรของคุณมีประเภทโพลีมอร์ฟิคx :: FromVar e => eเป็นต้นฉันไม่ได้ทดสอบว่ามันใช้งานได้ดีแค่ไหนตอนนี้ที่ฉันใช้โทรศัพท์