{-# LANGUAGE FlexibleInstances #-}
module FreeNum where
import Data.Functor.Free
import Control.Applicative
instance Num (Free Num a) where
Free l + Free r = Free $ (+) <$> l <*> r
Free l * Free r = Free $ (*) <$> l <*> r
Free l - Free r = Free $ (-) <$> l <*> r
negate (Free f) = Free $ negate <$> f
abs (Free f) = Free $ abs <$> f
signum (Free f) = Free $ signum <$> f
fromInteger i = Free $ pure (fromInteger i)
x, y :: Free Num String
x = return "x"
y = return "y"
expr :: Free Num String
expr = 1 + x * (3 - y)
-- Monadic bind is variable substitution
subst :: Free Num String -> Free Num a
subst e = e >>= \v -> case v of
"x" -> 10
_ -> 2
-- Closed expressions can be evaluated to any other instance of Num
result :: Int
result = convertClosed (subst expr)