Haskell thêm một kiểu đa hình

Oct 25 2020

Tôi đang cố gắng thêm dấu == đa hình vào kiểu dữ liệu. Tôi đã thêm POLYEQ Var Var vào dữ liệu Exp và thêm Eval1 và 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

Nhưng tôi nhận được lỗi followng;

Exp.hs: 37: 32: error:

• 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

Exp.hs: 37: 45: error:

• 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

Không thành công, mô-đun được tải: không có.

Làm cách nào để tạo dấu đa hình ==?


biên tập:

eval1:: Exp -> Bool
eval1 (POLYEQ e19 e20) = eval e19 == eval e20

Tệp tải ngay bây giờ, nhưng khi tôi chạy ti1 = POLYEQ (MyInt 4) (MyInt 7) theo sau bởi eval1 ti1, tôi gặp lỗi sau:

: 100: 7: error: • Không thể khớp với loại mong đợi '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

Trả lời

1 JonPurdy Oct 25 2020 at 20:25

Có một số vấn đề với mã của bạn. Đầu tiên, để giải quyết vấn đề thực tế của bạn, bạn nên tạo các trường của hàm POLYEQtạo kiểu Exp, không Var, nếu không, bạn sẽ chỉ có thể so sánh các biến.

Thứ hai, bạn không nên chia evalhàm thành nhiều định nghĩa như thế này. Có vẻ như bạn đã làm như vậy để trả về các loại kết quả khác nhau từ mỗi loại: Inthoặc Bool. Nhưng hiệu quả của việc viết mã của bạn theo cách này là tất cả các hàm này đều là một phần : eval0sẽ chỉ hoạt động trên một tập hợp con của các biểu thức và sẽ bị lỗi trên những người khác, và bạn không thể biết trước hàm nào để gọi một hàm tùy ý Expmà không kiểm tra nó trước.

Một cách tiếp cận thông thường đơn giản là thêm một loại giá trị có được từ đánh giá, ví dụ:

data Val
  = IntVal Int
  | BoolVal Bool

Với điều này, bạn có thể hợp nhất các hàm của mình thành một và gắn thẻ kết quả của mỗi trường hợp bằng hàm tạo thích hợp Val. Ngoài ra, bạn không cần đặt tên cho tất cả các biến của mình bằng các tên riêng biệt, vì chúng là cục bộ cho từng trường hợp.

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.

Đối với POLYEQtrường hợp này, bạn cần phải đối sánh kết quả đánh giá để khẳng định rằng chúng cùng loại và so sánh cho phù hợp:

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?

Tuy nhiên, điều này không mô tả cách đánh giá biểu thức lambda ( L) và các biến. Đối với điều đó, bạn sẽ cần thêm một đối số bổ sung để evalchứa môi trường biến (ví dụ: a [Val], nơi VZtìm kiếm từ đầu và VStìm kiếm trong đuôi) và một hàm tạo khác Valđể lưu trữ một giá trị hàm với môi trường của nó . Tuy nhiên, điều này nằm ngoài phạm vi câu hỏi hiện tại của bạn.