Reputation: 13908
This is a calculator that only sums numbers:
module Data.Calculator where
data Expr = Plus Expr Expr | Value Int
evaluate :: Expr -> Int
evaluate (Value a) = a
evaluate (Plus (Value a) (Value b)) = a + b
evaluate (Plus (Plus left right) (Value b)) = (evaluate left) + (evaluate right) + b
evaluate (Plus (Value a) (Plus left right)) = a + (evaluate left) + (evaluate right)
evaluate (Plus a@(Plus left right) b@(Plus left' right')) = (evaluate a) + (evaluate b)
The evaluate
function seems way to verbose. Ideally I'd like to define a typeclass both operators and then define Plus
as an instance of an operator, something like this:
class BinaryOp a where
apply :: a -> a -> Expr
instance BinaryOp Plus where
apply x y = x + y
But this obviously does not work because the type a
that BinaryOp
is defined with is an operator and not an operand.
How do I do this?
Upvotes: 1
Views: 216
Reputation: 173
Your evaluate
function can be just
evaluate :: Expr -> Int
evaluate (Value x) = x
evaluate (Plus x y) = evaluate x + evaluate y
as all cases are accounted for.
For per the typeclass, you cannot create an instance for Plus
since that's a constructor and you need to specify instances for types (in this case Expr
is the type, while Plus
and Value
are the constructors). If you wanted a typeclass that takes two elements of a certain type and produces an Int
, you could write something like this:
data Expr = Plus Expr Expr | Value Int
class BinaryOp a where
apply :: a -> a -> Int
instance BinaryOp Expr where
apply x y = evaluate $ Plus x y
Upvotes: 4