Haskell เพิ่มประเภท polymorphic

Oct 25 2020

ฉันกำลังพยายามเพิ่ม 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

คำตอบ

1 JonPurdy Oct 25 2020 at 20:25

มีปัญหาหลายประการเกี่ยวกับรหัสของคุณ ขั้นแรกในการแก้ปัญหาที่แท้จริงของคุณคุณควรสร้างฟิลด์ของตัว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เพื่อเก็บค่าฟังก์ชันพร้อมกับสภาพแวดล้อม . อย่างไรก็ตามนี่อยู่นอกเหนือขอบเขตของคำถามปัจจุบันของคุณ