dopatraman
dopatraman

Reputation: 13908

How to define a typeclass for a binary operator?

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

Answers (1)

Jolanda
Jolanda

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

Related Questions