Search code examples
haskelloperatorssymbolic-math

Idiomatic way to write math expression in Haskell


I want to write down math expressions using Haskell. For example:

foo = (3 * 'x' + 2 * 'y' -- => 3x+2y

Is there a way to rewrite the implementation from below in such way that Add and Mul could be replaced by operators + and * respectively?

data Expr = Const Integer
          | Var Char
          | Add Expr Expr
          | Mul Expr Expr
          deriving (Show)
 ...
 foo =  Add (Mul (Const 3)  (Var 'x')) (Mul (Const 3) (Var 'y'))

Ugly as hell. Using TypeOperators won't work too, it requires operators to be preceded by :.

infixl 4 :+:
infixl 5 :*:, :/:
infixr 6 :^:

data Expr = Const Integer
          | Var Char
          | Expr :+: Expr
          | Expr :*: Expr
          | Expr :^: Expr
          | Expr :/: Expr
          deriving (Eq, Show)

The declaration of expression would become:

foo = (Const 3 :*: Var 'x') :+: (Const 2 :*: Var 'y')

Less ugly, but still bad. Any ideas?


Solution

  • {-# LANGUAGE OverloadedStrings #-}
    
    import Data.String
    
    data Expr = Const Integer
              | Var Char
              | Add Expr Expr
              | Mul Expr Expr
              deriving (Show)
    
    instance Num Expr where
      (+) = Add
      (*) = Mul
      fromInteger = Const
      abs = undefined
      signum = undefined
      negate = undefined
    
    instance IsString Expr where
      fromString s = Var (head s)
    
    main = do
      let expr = 3 * "x" + 2 * "y" :: Expr
      print expr