```{-#LANGUAGE TemplateHaskell#-}
{-#LANGUAGE QuasiQuotes#-}

module Algebra.CAS.Core where

import Language.Haskell.TH
import Algebra.CAS.Type

exp2val :: Exp -> Value

exp2val (InfixE (Just a) (VarE op) (Just b))
| op == '(+) = exp2val a + exp2val b
| op == '(-) = exp2val a - exp2val b
| op == '(*) = exp2val a * exp2val b
| op == '(/) = exp2val a / exp2val b
| op == '(**) = exp2val a ** exp2val b
| otherwise = error "can not parse"

exp2val (AppE (VarE fun) a)
| fun ==  'log = Log \$ exp2val a
| fun ==  'sqrt = Sqrt \$ exp2val a
| fun ==  'exp = Exp \$ exp2val a
| fun ==  'sin = Sin \$ exp2val a
| fun ==  'cos = Cos \$ exp2val a
| fun ==  'tan = Tan \$ exp2val a
| fun ==  'asin = Asin \$ exp2val a
| fun ==  'acos = Acos \$ exp2val a
| fun ==  'atan = Atan \$ exp2val a
| fun ==  'sinh = Sinh \$ exp2val a
| fun ==  'cosh = Cosh \$ exp2val a
| fun ==  'tanh = Tanh \$ exp2val a
| fun ==  'asinh = Asinh \$ exp2val a
| fun ==  'acosh = Acosh \$ exp2val a
| fun ==  'atanh = Atanh \$ exp2val a
| fun ==  'negate = Neg \$ exp2val a
| otherwise = error "can not parse"
exp2val (LitE (IntegerL a)) = CI a
exp2val (LitE (RationalL a)) = C a
exp2val (VarE a) | a == 'pi = Pi
| otherwise = V a

exp2val a@_ = error \$ "can not parse:" ++ show a

val2exp :: Value -> Exp
val2exp (a :+: b) = (InfixE (Just (val2exp a)) (VarE '(+)) (Just (val2exp b)))
val2exp (a :-: b) = (InfixE (Just (val2exp a)) (VarE '(-)) (Just (val2exp b)))
val2exp (a :*: b) = (InfixE (Just (val2exp a)) (VarE '(*)) (Just (val2exp b)))
val2exp (a :/: b) = (InfixE (Just (val2exp a)) (VarE '(/)) (Just (val2exp b)))
val2exp (a :^: b) = (InfixE (Just (val2exp a)) (VarE '(**)) (Just (val2exp b)))

val2exp (Log a) = (AppE (VarE 'log) (val2exp a))
val2exp (Sqrt a) = (AppE (VarE 'sqrt) (val2exp a))
val2exp (Exp a) = (AppE (VarE 'exp) (val2exp a))
val2exp (Cos a) = (AppE (VarE 'cos) (val2exp a))
val2exp (Tan a) = (AppE (VarE 'tan) (val2exp a))
val2exp (Asin a) = (AppE (VarE 'asin) (val2exp a))
val2exp (Acos a) = (AppE (VarE 'acos) (val2exp a))
val2exp (Atan a) = (AppE (VarE 'atan) (val2exp a))
val2exp (Sinh a) = (AppE (VarE 'sinh) (val2exp a))
val2exp (Cosh a) = (AppE (VarE 'cosh) (val2exp a))
val2exp (Tanh a) = (AppE (VarE 'tanh) (val2exp a))
val2exp (Asinh a) = (AppE (VarE 'asinh) (val2exp a))
val2exp (Acosh a) = (AppE (VarE 'acosh) (val2exp a))
val2exp (Atanh a) = (AppE (VarE 'atanh) (val2exp a))
val2exp (Neg a) = (AppE (VarE 'negate) (val2exp a))

val2exp (CI a) = LitE (IntegerL a)
val2exp (C a) = LitE (RationalL a)
val2exp Pi = VarE 'pi
val2exp (V a) = VarE \$ a

val2exp a@_ = error \$ "can not parse:" ++ show a

lift  ::  Value -> Exp
lift  = val2exp
lift1 ::  (Value -> Value) -> Exp -> Exp
lift1 a b = val2exp \$ a (exp2val b)
lift2 ::  (Value -> Value -> Value) -> Exp -> Exp -> Exp
lift2 a b c = val2exp \$ a (exp2val b) (exp2val c)
lift3 ::  (Value -> Value -> Value -> Value) -> Exp -> Exp -> Exp -> Exp
lift3 a b c d = val2exp \$ a (exp2val b) (exp2val c) (exp2val d)

```