简体   繁体   English

Haskell 添加多态类型

[英]Haskell adding a polymorphic type

I am trying to add a polymorphic == to a data type.我正在尝试将多态 == 添加到数据类型。 I have added the POLYEQ Var Var to data Exp and added Eval1 and Eval2:我已将 POLYEQ Var Var 添加到数据 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

But I get the followng error;但是我得到以下错误;

Exp.hs:37:32: error: Exp.hs: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

Exp.hs:37:45: error: Exp.hs: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

Failed, modules loaded: none.失败,加载模块:无。

How can I make the == polymorphic?如何使 == 多态?


edit:编辑:

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

The file loads now, but when I run ti1 = POLYEQ (MyInt 4) (MyInt 7) followed by eval1 ti1 I get the following error:该文件现在加载,但是当我运行 ti1 = POLYEQ (MyInt 4) (MyInt 7) 后跟 eval1 ti1 时,出现以下错误:

:100:7: error: • Couldn't match expected type 'Exp' :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

There are several issues with your code.您的代码有几个问题。 First, to solve your actual problem, you should make the fields of the POLYEQ constructor of type Exp , not Var , otherwise you will only be able to compare variables.首先,要解决您的实际问题,您应该将POLYEQ构造函数的字段设为Exp类型,而不是Var类型,否则您将只能比较变量。

Second, you should not split the eval function into multiple definitions like this.其次,您不应该像这样将eval function 拆分为多个定义。 It looks like you've done so in order to return different types of results from each one: Int or Bool .看起来您这样做是为了从每个结果返回不同类型的结果: IntBool But the effect of writing your code this way is that all of these functions are partial : eval0 will only work on a subset of expressions, and will crash on others, and you can't know ahead of time which function to call on an arbitrary Exp without examining it first.但是以这种方式编写代码的效果是所有这些函数都是部分的: eval0对表达式的一个子集起作用,并且会在其他表达式上崩溃,并且您无法提前知道在任意一个上调用哪个 function Exp没有先检查它。

A simple conventional approach is to add a type of values resulting from evaluation, for example:一种简单的常规方法是添加一种类型的评估结果,例如:

data Val
  = IntVal Int
  | BoolVal Bool

With this, you can consolidate your functions into one, and tag the result of each case with the appropriate Val constructor.有了这个,您可以将您的函数合并为一个,并使用适当的Val构造函数标记每个案例的结果。 In addition, you don't need to name all of your variables with distinct names, since they're local to each case.此外,您不需要使用不同的名称来命名所有变量,因为它们对于每种情况都是局部的。

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.

For the POLYEQ case, you need to match on the results of evaluation to assert that they're the same type, and compare accordingly:对于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?

However, this doesn't describe how to evaluate lambda expressions ( L ) and variables.但是,这没有描述如何评估 lambda 表达式 ( L ) 和变量。 For that, you'll need to add an additional argument to eval containing the variable environment (for example, a [Val] , where VZ looks up from the head, and VS looks up within the tail), and another constructor for Val to store a function value with its environment.为此,您需要向包含变量环境的eval添加一个额外的参数(例如,一个[Val] ,其中VZ从头部向上查找,而VS在尾部查找),以及Val的另一个构造函数将 function 值与其环境一起存储。 However, this is beyond the scope of your current question.但是,这超出了您当前问题的 scope。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM