Haskell เพิ่มประเภท polymorphic
ฉันกำลังพยายามเพิ่ม polymorphic == ให้กับชนิดข้อมูล ฉันได้เพิ่ม POLYEQ Var Var ไปยัง data Exp และเพิ่ม Eval1 และ Eval2:
{-# LANGUAGE TypeSynonymInstances, FlexibleInstances #-}
data Exp = V Var
| B Bool
| L Exp
| A Exp Exp
| MyInt Int
| And Exp Exp
| Or Exp Exp
| Not Exp
| Mult Exp Exp
| UnaryNeg Exp
| LEQ Exp Exp
| LESST Exp Exp
| Add Exp Exp
| POLYEQ Var Var
data Var = VZ |VS Var
eval:: Exp -> Int
eval (MyInt e4) = e4
eval (UnaryNeg e10) = - (eval e10)
eval (Mult e11 e12) = eval e11 * eval e12
eval (Add e1 e2) = eval e1 + eval e2
eval0:: Exp -> Bool
eval0 (B e5) = e5
eval0 (Not e3) = not (eval0 e3)
eval0 (And e6 e7) = (eval0 e6) && (eval0 e7)
eval0 (Or e8 e9) = (eval0 e8) || (eval0 e9)
eval0 (LEQ e13 e14) = eval e13 <= eval e14
eval0 (LESST e15 e16) = eval e15 < eval e16
eval2:: Exp -> Var
eval2 (V e22) = e22
eval1:: a -> Bool
eval1 (POLYEQ e19 e20) = eval2 e19 == eval2 e20
แต่ฉันได้รับข้อผิดพลาดที่ตามมา
ประสบการณ์: 37: 32: ข้อผิดพลาด:
• Couldn't match expected type ‘Exp’ with actual type ‘Var’
• In the first argument of ‘eval2’, namely ‘e19’
In the first argument of ‘(==)’, namely ‘eval2 e19’
In the expression: eval2 e19 == eval2 e20
ประสบการณ์: 37: 45: ข้อผิดพลาด:
• Couldn't match expected type ‘Exp’ with actual type ‘Var’
• In the first argument of ‘eval2’, namely ‘e20’
In the second argument of ‘(==)’, namely ‘eval2 e20’
In the expression: eval2 e19 == eval2 e20
โหลดโมดูลล้มเหลว: ไม่มี
ฉันจะสร้าง == polymorphic ได้อย่างไร
แก้ไข:
eval1:: Exp -> Bool
eval1 (POLYEQ e19 e20) = eval e19 == eval e20
ไฟล์โหลดตอนนี้ แต่เมื่อฉันรัน ti1 = POLYEQ (MyInt 4) (MyInt 7) ตามด้วย eval1 ti1 ฉันได้รับข้อผิดพลาดต่อไปนี้:
: 100: 7: ข้อผิดพลาด: •ไม่สามารถจับคู่ประเภท 'Exp' ที่คาดไว้
with actual type ‘Exp -> Exp -> Exp’
• Probable cause: ‘POLYEQ’ is applied to too few arguments
In the first argument of ‘eval1’, namely ‘POLYEQ’
In the expression: eval1 POLYEQ
In an equation for ‘it’: it = eval1 POLYEQ
คำตอบ
มีปัญหาหลายประการเกี่ยวกับรหัสของคุณ ขั้นแรกในการแก้ปัญหาที่แท้จริงของคุณคุณควรสร้างฟิลด์ของตัวPOLYEQสร้างประเภทExpไม่ใช่Varมิฉะนั้นคุณจะสามารถเปรียบเทียบตัวแปรได้เท่านั้น
ประการที่สองคุณไม่ควรแยกevalฟังก์ชันออกเป็นหลาย ๆ คำจำกัดความเช่นนี้ มันดูเหมือนว่าคุณได้ทำเช่นนั้นเพื่อที่จะกลับแตกต่างกันของผลที่ได้จากแต่ละคน: หรือInt Boolแต่ผลของการเขียนโค้ดของคุณด้วยวิธีนี้ก็คือฟังก์ชั่นทั้งหมดเหล่านี้เป็นเพียงบางส่วน : eval0จะทำงานกับนิพจน์ส่วนย่อยเท่านั้นและจะขัดข้องกับผู้อื่นและคุณไม่สามารถรู้ล่วงหน้าได้ว่าจะเรียกใช้ฟังก์ชันใดโดยพลการตรวจสอบก่อนExp
แนวทางง่ายๆคือการเพิ่มประเภทของค่าที่เกิดจากการประเมินตัวอย่างเช่น:
data Val
= IntVal Int
| BoolVal Bool
ด้วยวิธีนี้คุณสามารถรวมฟังก์ชันของคุณเป็นหนึ่งเดียวและแท็กผลลัพธ์ของแต่ละกรณีด้วยตัวValสร้างที่เหมาะสม นอกจากนี้คุณไม่จำเป็นต้องตั้งชื่อตัวแปรทั้งหมดด้วยชื่อที่แตกต่างกันเนื่องจากเป็นชื่อท้องถิ่นสำหรับแต่ละกรณี
eval :: Exp -> Val
-- Evaluation of literals: tag the value with its type.
eval (MyInt i) = IntVal i
eval (B b) = BoolVal b
-- Evaluation of integer operations: match on ‘IntVal’.
-- This will raise an error if the expression did not return an integer.
eval (UnaryNeg e) = let
IntVal i = eval e -- Unwrap result, asserting that it’s an integer.
in IntVal (- i) -- Rewrap in ‘IntVal’ after applying negation.
eval (Mult e1 e2) = let
IntVal i1 = eval e1
IntVal i2 = eval e2
in IntVal (i1 * i2)
-- Instead of just crashing, you may use explicit
-- pattern matching and handle the type error:
eval (Add e1 e2) = case (eval e1, eval e2) of
(IntVal i1, IntVal i2) -> IntVal (i1 + i2)
_ -> ... -- Decide what to do in the error case.
-- Fill in the remaining cases for each ‘Exp’ constructor.
ในPOLYEQกรณีนี้คุณต้องจับคู่ผลการประเมินเพื่อยืนยันว่าเป็นประเภทเดียวกันและเปรียบเทียบตามนั้น:
eval (POLYEQ e1 e2) = case (eval e1, eval e2) of
(IntVal i1, IntVal i2) -> BoolVal (i1 == i2)
(BoolVal b1, BoolVal b2) -> BoolVal (b1 == b2)
_ -> ... -- What do you want to do in this case?
-- Return ‘BoolVal False’, raise an error, or something else?
อย่างไรก็ตามนี่ไม่ได้อธิบายถึงวิธีการประเมินนิพจน์แลมบ์ดา ( L) และตัวแปร ด้วยเหตุนี้คุณจะต้องเพิ่มอาร์กิวเมนต์เพิ่มเติมเพื่อให้evalมีสภาพแวดล้อมตัวแปร (ตัวอย่างเช่น a [Val]ซึ่งVZมองขึ้นจากส่วนหัวและVSค้นหาภายในส่วนท้าย) และตัวสร้างอีกตัวValเพื่อเก็บค่าฟังก์ชันพร้อมกับสภาพแวดล้อม . อย่างไรก็ตามนี่อยู่นอกเหนือขอบเขตของคำถามปัจจุบันของคุณ