Haskell: Using the same operator on different types in a function

I'm writing a simple interpreter in Haskell. I have 3 possible variable types: bool , int and string . To avoid repetition in evaluating comparisons, I've written a function that takes 2 expressions and an operator:

data Value = IntVal Integer
           | StringVal String
           | BoolVal Bool
           | ...

evalComparison :: Ord a => Exp -> (a -> a -> Bool) -> Exp -> Result Value
evalComparison expr1 op expr2 = do
  val1 <- evalExp expr1
  val2 <- evalExp expr2
  return $ BoolVal $
    case (val1, val2) of
      (IntVal i1, IntVal i2)       -> op i1 i2 (*)
      (StringVal s1, StringVal s2) -> op s1 s2 (**)
      (BoolVal b1, BoolVal b2)     -> op b1 b2 (***)
      otherwise                    -> error "Expected values of the same type!"

It's intended usage is, for example:

evalExp :: Exp -> Result Value
...
evalExp (ELessThen e1 e2) = evalComparison e1 (<) e2

(And so on for other comparison operators).

The problem is - it doesn't work. GHC says it couldn't match type Integer with [Char] in line (**) and similarly Integer with Bool in line (***) .

I think I know where the problem lies: once the a from the operator's type is determined as Integer in line (*) , it cannot be changed. So my question is twofold:

  • Why does this problem arise, provided that the result type ( Bool ) is always the same regardless of the operator's arguments' types?

  • What can be done to make this work?


  • The type signature a -> a -> Bool says that there must exist some type a for which op has that type. But you want this to work for more than one type a . You can't do that in Haskell '98.

    If you turn on rank-2 types (or rank-N types), then you can do

    evalComparison :: Exp -> (forall a. a -> a -> Bool) -> Exp -> Result Value
    

    This says that whatever you pass in as op has to work for multiple types a . In fact, it says that op has to work for all possible types a . But that's probably too much. What you want is probably closer to

    evalComparison :: Exp -> (forall a. Ord a => a -> a -> Bool) -> Exp -> Result Value

    This says that op has to work for every possible a that implements Ord .

    Although frankly at that point, you might as well just call compare explicitly in your case-expression. Have evalComparison return an Ordering , and then apply a Ordering -> Result Value to that. Ordering is only one type, which should make things simpler.

    链接地址: http://www.djcxy.com/p/33156.html

    上一篇: 在Haskell中打印空列表

    下一篇: Haskell:在函数的不同类型中使用相同的运算符