ปัญหา
พิจารณาปัญหาการออกแบบต่อไปนี้ใน 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
เป็นต้นฉันไม่ได้ทดสอบว่ามันใช้งานได้ดีแค่ไหนตอนนี้ที่ฉันใช้โทรศัพท์