{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE OverloadedStrings #-}
{-# OPTIONS_GHC -Wcpp-undef #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
{-# OPTIONS_HADDOCK show-extensions #-}

-- | Module    :  Debug.SimpleExpr.Expr
-- Copyright   :  (C) 2023 Alexey Tochin
-- License     :  BSD3 (see the file LICENSE)
-- Maintainer  :  Alexey Tochin <Alexey.Tochin@gmail.com>
--
-- Simple expressions base types and manipulations.
module Debug.SimpleExpr.Expr
  ( -- * Expression manipulation
    number,
    variable,
    unaryFunc,
    binaryFunc,
    simplifyExpr,
    simplifyStep,
    simplify,

    -- * Base types
    SimpleExprF (NumberF, VariableF, SymbolicFuncF),
    SimpleExpr,
    SE,
    Expr,

    -- * Auxiliary functions
    ListOf,
    content,
    dependencies,
    showWithBrackets,
  )
where

import Control.ExtendableMap (ExtandableMap, extendMap)
import Control.Monad (guard)
import Control.Monad.Fix (fix)
import Data.Fix (Fix (Fix, unFix))
import Data.Functor.Classes (Eq1, liftEq)
import Data.Hashable (Hashable(hashWithSalt))
import Data.Hashable.Lifted (Hashable1(liftHashWithSalt))
import Data.Hashable.Generic (genericLiftHashWithSalt)
import Data.List (intercalate, null, uncons, unsnoc, (++))
import Data.Maybe (isJust)
import GHC.Base
  ( Applicative (pure),
    Bool(False),
    Eq ((==)),
    Functor (fmap),
    Maybe (Just, Nothing),
    String,
    not,
    seq,
    ($),
    (&&),
    (.),
    (<>),
    (>=)
  )
import GHC.Generics (Generic1)
import GHC.Natural (Natural)
import GHC.Num (Num)
import GHC.Show (Show (show))
import NumHask
  ( Additive,
    Divisive,
    ExpField,
    FromInteger,
    Multiplicative,
    Subtractive,
    TrigField,
    fromIntegral,
    one,
    zero,
  )
import qualified NumHask as NH
import qualified Prelude as P

-- | Expression F-algebra functional.
data SimpleExprF a
  = NumberF Natural
  | VariableF String
  | SymbolicFuncF String [a]
  deriving ((forall a b. (a -> b) -> SimpleExprF a -> SimpleExprF b)
-> (forall a b. a -> SimpleExprF b -> SimpleExprF a)
-> Functor SimpleExprF
forall a b. a -> SimpleExprF b -> SimpleExprF a
forall a b. (a -> b) -> SimpleExprF a -> SimpleExprF b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
$cfmap :: forall a b. (a -> b) -> SimpleExprF a -> SimpleExprF b
fmap :: forall a b. (a -> b) -> SimpleExprF a -> SimpleExprF b
$c<$ :: forall a b. a -> SimpleExprF b -> SimpleExprF a
<$ :: forall a b. a -> SimpleExprF b -> SimpleExprF a
Functor, SimpleExprF a -> SimpleExprF a -> Bool
(SimpleExprF a -> SimpleExprF a -> Bool)
-> (SimpleExprF a -> SimpleExprF a -> Bool) -> Eq (SimpleExprF a)
forall a. Eq a => SimpleExprF a -> SimpleExprF a -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: forall a. Eq a => SimpleExprF a -> SimpleExprF a -> Bool
== :: SimpleExprF a -> SimpleExprF a -> Bool
$c/= :: forall a. Eq a => SimpleExprF a -> SimpleExprF a -> Bool
/= :: SimpleExprF a -> SimpleExprF a -> Bool
Eq, (forall a. SimpleExprF a -> Rep1 SimpleExprF a)
-> (forall a. Rep1 SimpleExprF a -> SimpleExprF a)
-> Generic1 SimpleExprF
forall a. Rep1 SimpleExprF a -> SimpleExprF a
forall a. SimpleExprF a -> Rep1 SimpleExprF a
forall k (f :: k -> *).
(forall (a :: k). f a -> Rep1 f a)
-> (forall (a :: k). Rep1 f a -> f a) -> Generic1 f
$cfrom1 :: forall a. SimpleExprF a -> Rep1 SimpleExprF a
from1 :: forall a. SimpleExprF a -> Rep1 SimpleExprF a
$cto1 :: forall a. Rep1 SimpleExprF a -> SimpleExprF a
to1 :: forall a. Rep1 SimpleExprF a -> SimpleExprF a
Generic1)

instance Hashable1 SimpleExprF where
  liftHashWithSalt :: forall a. (Int -> a -> Int) -> Int -> SimpleExprF a -> Int
liftHashWithSalt = (Int -> a -> Int) -> Int -> SimpleExprF a -> Int
forall (t :: * -> *) a.
(Generic1 t, GHashable One (Rep1 t)) =>
(Int -> a -> Int) -> Int -> t a -> Int
genericLiftHashWithSalt

instance Hashable a => Hashable (SimpleExprF a) where
  hashWithSalt :: Int -> SimpleExprF a -> Int
hashWithSalt Int
salt (NumberF Natural
n) = Int -> Natural -> Int
forall a. Hashable a => Int -> a -> Int
hashWithSalt Int
salt Natural
n
  hashWithSalt Int
salt (VariableF String
s) = Int -> String -> Int
forall a. Hashable a => Int -> a -> Int
hashWithSalt Int
salt String
s
  hashWithSalt Int
salt (SymbolicFuncF String
name [a]
xs) =
    Int
salt Int -> String -> Int
forall a. Hashable a => Int -> a -> Int
`hashWithSalt` String
name Int -> [a] -> Int
forall a. Hashable a => Int -> a -> Int
`hashWithSalt` [a]
xs

-- | Equality comparison for `SimpleExprF` lifted over its parameter.
instance Eq1 SimpleExprF where
  liftEq :: (a -> b -> Bool) -> SimpleExprF a -> SimpleExprF b -> Bool
  liftEq :: forall a b.
(a -> b -> Bool) -> SimpleExprF a -> SimpleExprF b -> Bool
liftEq a -> b -> Bool
eq SimpleExprF a
e1 SimpleExprF b
e2 = case (SimpleExprF a
e1, SimpleExprF b
e2) of
    (NumberF Natural
n1, NumberF Natural
n2) -> Natural
n1 Natural -> Natural -> Bool
forall a. Eq a => a -> a -> Bool
== Natural
n2
    (VariableF String
v1, VariableF String
v2) -> String
v1 String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== String
v2
    (SymbolicFuncF String
name1 [a]
args1, SymbolicFuncF String
name2 [b]
args2) -> (String
name1 String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== String
name2) Bool -> Bool -> Bool
&& (a -> b -> Bool) -> [a] -> [b] -> Bool
forall a b. (a -> b -> Bool) -> [a] -> [b] -> Bool
forall (f :: * -> *) a b.
Eq1 f =>
(a -> b -> Bool) -> f a -> f b -> Bool
liftEq a -> b -> Bool
eq [a]
args1 [b]
args2
    (SimpleExprF a, SimpleExprF b)
_ -> Bool
False

-- | `SimpleExprF` instance of `NumHask.FromIntegral` typeclass.
instance
  (NH.FromIntegral Natural n) =>
  NH.FromIntegral (SimpleExprF a) n
  where
  fromIntegral :: n -> SimpleExprF a
fromIntegral = Natural -> SimpleExprF a
forall a. Natural -> SimpleExprF a
NumberF (Natural -> SimpleExprF a) -> (n -> Natural) -> n -> SimpleExprF a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. n -> Natural
forall a b. FromIntegral a b => b -> a
fromIntegral

-- | Simple expression type, see
-- [tutorial](Debug.SimpleExpr.Tutorial.hs)
type SimpleExpr = Fix SimpleExprF

-- | Short type alias for `SimpleExpr`.
type SE = SimpleExpr

-- | Initializes a single integer number expression.
--
-- ==== __Examples of usage__
--
-- >>> a = number 42
-- >>> a
-- 42
-- >>> :t a
-- a :: SimpleExpr
number :: Natural -> SimpleExpr
number :: Natural -> SimpleExpr
number Natural
n = SimpleExprF SimpleExpr -> SimpleExpr
forall (f :: * -> *). f (Fix f) -> Fix f
Fix (Natural -> SimpleExprF SimpleExpr
forall a. Natural -> SimpleExprF a
NumberF Natural
n)

-- | Initializes a single symbolic variable expression.
--
-- ==== __Examples of usage__
--
-- >>> x = variable "x"
-- >>> x
-- x
-- >>> :t x
-- x :: SimpleExpr
variable :: String -> SimpleExpr
variable :: String -> SimpleExpr
variable String
name = SimpleExprF SimpleExpr -> SimpleExpr
forall (f :: * -> *). f (Fix f) -> Fix f
Fix (String -> SimpleExprF SimpleExpr
forall a. String -> SimpleExprF a
VariableF String
name)

-- | Returns the list of head dependencies of an expression.
--
-- ==== __Examples of usage__
--
-- >>> import Prelude (($), id)
-- >>> import NumHask ((+), (*))
--
-- >>> dependencies (variable "x" + (variable "y" * variable "z"))
-- [x,y*z]
dependencies :: SimpleExpr -> [SimpleExpr]
dependencies :: SimpleExpr -> [SimpleExpr]
dependencies (Fix SimpleExprF SimpleExpr
e) = case SimpleExprF SimpleExpr
e of
  NumberF Natural
_ -> []
  VariableF String
_ -> []
  SymbolicFuncF String
_ [SimpleExpr]
args -> [SimpleExpr]
args

-- | `SimpleExpr` instance of `NumHask.FromIntegral` typeclass.
instance
  (NH.FromIntegral Natural n) =>
  NH.FromIntegral SimpleExpr n
  where
  fromIntegral :: n -> SimpleExpr
fromIntegral = Natural -> SimpleExpr
number (Natural -> SimpleExpr) -> (n -> Natural) -> n -> SimpleExpr
forall b c a. (b -> c) -> (a -> b) -> a -> c
. n -> Natural
forall a b. FromIntegral a b => b -> a
fromIntegral

-- | Entity that is representable as a list of in general other entities.
-- In particular, @X@ is a list of single @[X]@, see the example below.
--
-- ==== __Examples of usage__
--
-- >>> data Atom = Atom String deriving Show
-- >>> type Particle = ListOf Atom
--
-- >>> content (Atom "He") :: [Atom]
-- [Atom "He"]
--
-- >>> content (Atom "H", Atom "H") :: [Atom]
-- [Atom "H",Atom "H"]
--
-- >>> content [Atom "H", Atom "O", Atom "H"] :: [Atom]
-- [Atom "H",Atom "O",Atom "H"]
class ListOf inner outer where
  -- | Returns a list of entities the argument consists of.
  content :: outer -> [inner]

-- | Base case instance of `ListOf`.
instance ListOf inner () where
  content :: () -> [inner]
content = [inner] -> () -> [inner]
forall a b. a -> b -> a
P.const []

-- | Identity instance of `ListOf`.
instance ListOf inner inner where
  content :: inner -> [inner]
content inner
e = [inner
e]

-- | Tuple instance of `ListOf`.
instance
  (ListOf inner outer1, ListOf inner outer2) =>
  ListOf inner (outer1, outer2)
  where
  content :: (outer1, outer2) -> [inner]
content (outer1
x1, outer2
x2) = outer1 -> [inner]
forall inner outer. ListOf inner outer => outer -> [inner]
content outer1
x1 [inner] -> [inner] -> [inner]
forall a. [a] -> [a] -> [a]
++ outer2 -> [inner]
forall inner outer. ListOf inner outer => outer -> [inner]
content outer2
x2

-- | Triple instance of `ListOf`.
instance
  (ListOf inner outer1, ListOf inner outer2, ListOf inner outer3) =>
  ListOf inner (outer1, outer2, outer3)
  where
  content :: (outer1, outer2, outer3) -> [inner]
content (outer1
x1, outer2
x2, outer3
x3) = outer1 -> [inner]
forall inner outer. ListOf inner outer => outer -> [inner]
content outer1
x1 [inner] -> [inner] -> [inner]
forall a. [a] -> [a] -> [a]
++ outer2 -> [inner]
forall inner outer. ListOf inner outer => outer -> [inner]
content outer2
x2 [inner] -> [inner] -> [inner]
forall a. [a] -> [a] -> [a]
++ outer3 -> [inner]
forall inner outer. ListOf inner outer => outer -> [inner]
content outer3
x3

-- | 4-tuple instance of `ListOf`.
instance
  (ListOf inner outer1, ListOf inner outer2, ListOf inner outer3, ListOf inner outer4) =>
  ListOf inner (outer1, outer2, outer3, outer4)
  where
  content :: (outer1, outer2, outer3, outer4) -> [inner]
content (outer1
x1, outer2
x2, outer3
x3, outer4
x4) = outer1 -> [inner]
forall inner outer. ListOf inner outer => outer -> [inner]
content outer1
x1 [inner] -> [inner] -> [inner]
forall a. [a] -> [a] -> [a]
++ outer2 -> [inner]
forall inner outer. ListOf inner outer => outer -> [inner]
content outer2
x2 [inner] -> [inner] -> [inner]
forall a. [a] -> [a] -> [a]
++ outer3 -> [inner]
forall inner outer. ListOf inner outer => outer -> [inner]
content outer3
x3 [inner] -> [inner] -> [inner]
forall a. [a] -> [a] -> [a]
++ outer4 -> [inner]
forall inner outer. ListOf inner outer => outer -> [inner]
content outer4
x4

-- | 5-tuple instance of `ListOf`.
instance
  (ListOf inner outer1, ListOf inner outer2, ListOf inner outer3, ListOf inner outer4, ListOf inner outer5) =>
  ListOf inner (outer1, outer2, outer3, outer4, outer5)
  where
  content :: (outer1, outer2, outer3, outer4, outer5) -> [inner]
content (outer1
x1, outer2
x2, outer3
x3, outer4
x4, outer5
x5) = outer1 -> [inner]
forall inner outer. ListOf inner outer => outer -> [inner]
content outer1
x1 [inner] -> [inner] -> [inner]
forall a. [a] -> [a] -> [a]
++ outer2 -> [inner]
forall inner outer. ListOf inner outer => outer -> [inner]
content outer2
x2 [inner] -> [inner] -> [inner]
forall a. [a] -> [a] -> [a]
++ outer3 -> [inner]
forall inner outer. ListOf inner outer => outer -> [inner]
content outer3
x3 [inner] -> [inner] -> [inner]
forall a. [a] -> [a] -> [a]
++ outer4 -> [inner]
forall inner outer. ListOf inner outer => outer -> [inner]
content outer4
x4 [inner] -> [inner] -> [inner]
forall a. [a] -> [a] -> [a]
++ outer5 -> [inner]
forall inner outer. ListOf inner outer => outer -> [inner]
content outer5
x5

-- | List `[]` instance of `ListOf`.
instance (ListOf inner outer) => ListOf inner [outer] where
  content :: [outer] -> [inner]
content = (outer -> [inner]
forall inner outer. ListOf inner outer => outer -> [inner]
content (outer -> [inner]) -> [outer] -> [inner]
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
P.=<<)

-- | Expression typeclass.
-- It includes `SimpleExpr` as well as list and tuples of `SimpleExpr` etc.
type Expr = ListOf SimpleExpr

-- | `SimpleExpr` instance of `Show` typeclass.
instance {-# OVERLAPPING #-} Show SimpleExpr where
  show :: SimpleExpr -> String
show (Fix SimpleExprF SimpleExpr
e) = case SimpleExprF SimpleExpr
e of
    NumberF Natural
n -> Natural -> String
forall a. Show a => a -> String
show Natural
n
    VariableF String
name -> String
name
    sf :: SimpleExprF SimpleExpr
sf@(SymbolicFuncF String
name [SimpleExpr]
args) -> case SimpleExpr -> Maybe (String, SimpleExpr, SimpleExpr)
matchBinnaryFuncPattern (SimpleExprF SimpleExpr -> SimpleExpr
forall (f :: * -> *). f (Fix f) -> Fix f
Fix SimpleExprF SimpleExpr
sf) of
      Just (String
name', SimpleExpr
leftArg, SimpleExpr
rightArg) -> SimpleExpr -> String
showWithBrackets SimpleExpr
leftArg String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
name' String -> ShowS
forall a. Semigroup a => a -> a -> a
<> SimpleExpr -> String
showWithBrackets SimpleExpr
rightArg
      Maybe (String, SimpleExpr, SimpleExpr)
Nothing -> String
name String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
"(" String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
intercalate String
"," ((SimpleExpr -> String) -> [SimpleExpr] -> [String]
forall a b. (a -> b) -> [a] -> [b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap SimpleExpr -> String
forall a. Show a => a -> String
show [SimpleExpr]
args) String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
")"

-- | Checks whether expression needs brackets in a context like binary function argument.
needBrackets :: SimpleExpr -> Bool
needBrackets :: SimpleExpr -> Bool
needBrackets = Maybe (String, SimpleExpr, SimpleExpr) -> Bool
forall a. Maybe a -> Bool
isJust (Maybe (String, SimpleExpr, SimpleExpr) -> Bool)
-> (SimpleExpr -> Maybe (String, SimpleExpr, SimpleExpr))
-> SimpleExpr
-> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SimpleExpr -> Maybe (String, SimpleExpr, SimpleExpr)
matchBinnaryFuncPattern

-- | Shows expression adding brackets if it is needed for a context.
showWithBrackets :: SimpleExpr -> String
showWithBrackets :: SimpleExpr -> String
showWithBrackets SimpleExpr
e =
  if SimpleExpr -> Bool
needBrackets SimpleExpr
e
    then String
"(" String -> ShowS
forall a. Semigroup a => a -> a -> a
<> SimpleExpr -> String
forall a. Show a => a -> String
show SimpleExpr
e String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
")"
    else SimpleExpr -> String
forall a. Show a => a -> String
show SimpleExpr
e

-- | Matches binary function pattern.
matchBinnaryFuncPattern :: SimpleExpr -> Maybe (String, SimpleExpr, SimpleExpr)
matchBinnaryFuncPattern :: SimpleExpr -> Maybe (String, SimpleExpr, SimpleExpr)
matchBinnaryFuncPattern (Fix (SymbolicFuncF String
name [SimpleExpr
x, SimpleExpr
y])) = do
  (Char
first, String
rest1) <- String -> Maybe (Char, String)
forall a. [a] -> Maybe (a, [a])
uncons String
name
  (String
body, Char
lastCh) <- String -> Maybe (String, Char)
forall a. [a] -> Maybe ([a], a)
unsnoc String
rest1
  Bool -> Maybe ()
forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Bool -> Maybe ()) -> Bool -> Maybe ()
forall a b. (a -> b) -> a -> b
$ Char
first Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
'('
  Bool -> Maybe ()
forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Bool -> Maybe ()) -> Bool -> Maybe ()
forall a b. (a -> b) -> a -> b
$ Char
lastCh Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
')'
  Bool -> Maybe ()
forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Bool -> Maybe ()) -> Bool -> Maybe ()
forall a b. (a -> b) -> a -> b
$ Bool -> Bool
not (String -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null String
body)
  (String, SimpleExpr, SimpleExpr)
-> Maybe (String, SimpleExpr, SimpleExpr)
forall a. a -> Maybe a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (String
body, SimpleExpr
x, SimpleExpr
y)
matchBinnaryFuncPattern SimpleExpr
_ = Maybe (String, SimpleExpr, SimpleExpr)
forall a. Maybe a
Nothing

-- | Inituialize unarry function
--
-- ==== __Examples of usage__
--
-- >>> x = variable "x"
-- >>> f = unaryFunc "f"
-- >>> f x
-- f(x)
-- >>> :t x
-- x :: SimpleExpr
-- >>> :t f
-- f :: SimpleExpr -> SimpleExpr
unaryFunc :: String -> SimpleExpr -> SimpleExpr
unaryFunc :: String -> SimpleExpr -> SimpleExpr
unaryFunc String
name SimpleExpr
x = SimpleExprF SimpleExpr -> SimpleExpr
forall (f :: * -> *). f (Fix f) -> Fix f
Fix (String -> [SimpleExpr] -> SimpleExprF SimpleExpr
forall a. String -> [a] -> SimpleExprF a
SymbolicFuncF String
name [SimpleExpr
x])

-- | Inituialize unarry function
--
-- ==== __Examples of usage__
--
-- >>> x = variable "x"
-- >>> y = variable "y"
-- >>> (-*-) = binaryFunc "-*-"
-- >>> x -*- y
-- x-*-y
-- >>> :t x
-- x :: SimpleExpr
-- >>> :t (-*-)
-- (-*-) :: SimpleExpr -> SimpleExpr -> SimpleExpr
-- >>> :t x-*-y
-- x-*-y :: SimpleExpr
binaryFunc :: String -> SimpleExpr -> SimpleExpr -> SimpleExpr
binaryFunc :: String -> SimpleExpr -> SimpleExpr -> SimpleExpr
binaryFunc String
name SimpleExpr
x SimpleExpr
y = SimpleExprF SimpleExpr -> SimpleExpr
forall (f :: * -> *). f (Fix f) -> Fix f
Fix (SimpleExprF SimpleExpr -> SimpleExpr)
-> SimpleExprF SimpleExpr -> SimpleExpr
forall a b. (a -> b) -> a -> b
$ String -> [SimpleExpr] -> SimpleExprF SimpleExpr
forall a. String -> [a] -> SimpleExprF a
SymbolicFuncF (String
"(" String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
name String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
")") [SimpleExpr
x, SimpleExpr
y]

-- | `SimpleExpr` instance of `NumHask.FromInteger` typeclass.
instance FromInteger SimpleExpr where
  fromInteger :: Integer -> SimpleExpr
fromInteger Integer
n =
    if Integer
n Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
>= Integer
0
      then Natural -> SimpleExpr
number (Natural -> SimpleExpr) -> Natural -> SimpleExpr
forall a b. (a -> b) -> a -> b
$ Integer -> Natural
forall a b. FromIntegral a b => b -> a
fromIntegral Integer
n
      else SimpleExpr -> SimpleExpr
forall a. Subtractive a => a -> a
NH.negate (SimpleExpr -> SimpleExpr) -> SimpleExpr -> SimpleExpr
forall a b. (a -> b) -> a -> b
$ Natural -> SimpleExpr
number (Natural -> SimpleExpr) -> Natural -> SimpleExpr
forall a b. (a -> b) -> a -> b
$ Integer -> Natural
forall a b. FromIntegral a b => b -> a
fromIntegral (Integer -> Natural) -> Integer -> Natural
forall a b. (a -> b) -> a -> b
$ Integer -> Integer
forall a. Num a => a -> a
P.abs Integer
n

-- | `SimpleExpr` instance of `NumHask.Additive` typeclass.
instance Additive SimpleExpr where
  zero :: SimpleExpr
zero = Natural -> SimpleExpr
number Natural
0
  + :: SimpleExpr -> SimpleExpr -> SimpleExpr
(+) = String -> SimpleExpr -> SimpleExpr -> SimpleExpr
binaryFunc String
"+"

-- | `SimpleExpr` instance of `NumHask.Subtractive` typeclass.
instance Subtractive SimpleExpr where
  negate :: SimpleExpr -> SimpleExpr
negate = String -> SimpleExpr -> SimpleExpr
unaryFunc String
"-"
  (-) = String -> SimpleExpr -> SimpleExpr -> SimpleExpr
binaryFunc String
"-"

-- | `SimpleExpr` instance of `NumHask.Multiplicative` typeclass.
instance Multiplicative SimpleExpr where
  one :: SimpleExpr
one = Natural -> SimpleExpr
number Natural
1
  * :: SimpleExpr -> SimpleExpr -> SimpleExpr
(*) = String -> SimpleExpr -> SimpleExpr -> SimpleExpr
binaryFunc String
"*"

-- | `SimpleExpr` instance of `NumHask.Divisive` typeclass.
instance Divisive SimpleExpr where
  / :: SimpleExpr -> SimpleExpr -> SimpleExpr
(/) = String -> SimpleExpr -> SimpleExpr -> SimpleExpr
binaryFunc String
"/"

-- | `SimpleExpr` instance of `NumHask.ExpField` typeclass.
instance ExpField SimpleExpr where
  exp :: SimpleExpr -> SimpleExpr
exp = String -> SimpleExpr -> SimpleExpr
unaryFunc String
"exp"
  log :: SimpleExpr -> SimpleExpr
log = String -> SimpleExpr -> SimpleExpr
unaryFunc String
"log"
  ** :: SimpleExpr -> SimpleExpr -> SimpleExpr
(**) = String -> SimpleExpr -> SimpleExpr -> SimpleExpr
binaryFunc String
"^"
  sqrt :: SimpleExpr -> SimpleExpr
sqrt = String -> SimpleExpr -> SimpleExpr
unaryFunc String
"sqrt"

-- | `SimpleExpr` instance of `NumHask.TrigField` typeclass.
instance TrigField SimpleExpr where
  pi :: SimpleExpr
pi = String -> SimpleExpr
variable String
"pi"
  sin :: SimpleExpr -> SimpleExpr
sin = String -> SimpleExpr -> SimpleExpr
unaryFunc String
"sin"
  cos :: SimpleExpr -> SimpleExpr
cos = String -> SimpleExpr -> SimpleExpr
unaryFunc String
"cos"
  tan :: SimpleExpr -> SimpleExpr
tan = String -> SimpleExpr -> SimpleExpr
unaryFunc String
"tg"
  asin :: SimpleExpr -> SimpleExpr
asin = String -> SimpleExpr -> SimpleExpr
unaryFunc String
"arcsin"
  acos :: SimpleExpr -> SimpleExpr
acos = String -> SimpleExpr -> SimpleExpr
unaryFunc String
"arccos"
  atan :: SimpleExpr -> SimpleExpr
atan = String -> SimpleExpr -> SimpleExpr
unaryFunc String
"arctan"
  sinh :: SimpleExpr -> SimpleExpr
sinh = String -> SimpleExpr -> SimpleExpr
unaryFunc String
"sh"
  cosh :: SimpleExpr -> SimpleExpr
cosh = String -> SimpleExpr -> SimpleExpr
unaryFunc String
"ch"
  tanh :: SimpleExpr -> SimpleExpr
tanh = String -> SimpleExpr -> SimpleExpr
unaryFunc String
"th"
  atan2 :: SimpleExpr -> SimpleExpr -> SimpleExpr
atan2 SimpleExpr
a SimpleExpr
b = SimpleExprF SimpleExpr -> SimpleExpr
forall (f :: * -> *). f (Fix f) -> Fix f
Fix (SimpleExprF SimpleExpr -> SimpleExpr)
-> SimpleExprF SimpleExpr -> SimpleExpr
forall a b. (a -> b) -> a -> b
$ String -> [SimpleExpr] -> SimpleExprF SimpleExpr
forall a. String -> [a] -> SimpleExprF a
SymbolicFuncF String
"atan2" [SimpleExpr
a, SimpleExpr
b]
  asinh :: SimpleExpr -> SimpleExpr
asinh = String -> SimpleExpr -> SimpleExpr
unaryFunc String
"arcsh"
  acosh :: SimpleExpr -> SimpleExpr
acosh = String -> SimpleExpr -> SimpleExpr
unaryFunc String
"arcch"
  atanh :: SimpleExpr -> SimpleExpr
atanh = String -> SimpleExpr -> SimpleExpr
unaryFunc String
"arcth"

-- | Numeric typeclass instance for `SimpleExpr`.
--
-- This instance enables standard numeric operations on symbolic expressions,
-- allowing for more natural mathematical notation in symbolic computations.
--
-- ==== __Examples of usage__
--
-- >>> import GHC.Num ((+))
--
-- The primary benefit of this instance is enabling direct use of numeric
-- literals in symbolic expressions without explicit conversion. This allows
-- you to write natural mathematical expressions:
--
-- >>> x = variable "x"
-- >>> x + 1
-- x+1
--
-- This concise notation is equivalent to the more verbose explicit form:
--
-- >>> x + (number 1)
-- x+1
instance Num SimpleExpr where
  + :: SimpleExpr -> SimpleExpr -> SimpleExpr
(+) = SimpleExpr -> SimpleExpr -> SimpleExpr
forall a. Additive a => a -> a -> a
(NH.+)
  (-) = SimpleExpr -> SimpleExpr -> SimpleExpr
forall a. Subtractive a => a -> a -> a
(NH.-)
  * :: SimpleExpr -> SimpleExpr -> SimpleExpr
(*) = SimpleExpr -> SimpleExpr -> SimpleExpr
forall a. Multiplicative a => a -> a -> a
(NH.*)
  negate :: SimpleExpr -> SimpleExpr
negate = SimpleExpr -> SimpleExpr
forall a. Subtractive a => a -> a
NH.negate
  abs :: SimpleExpr -> SimpleExpr
abs = String -> SimpleExpr -> SimpleExpr
unaryFunc String
"abs"
  signum :: SimpleExpr -> SimpleExpr
signum = String -> SimpleExpr -> SimpleExpr
unaryFunc String
"sign"
  fromInteger :: Integer -> SimpleExpr
fromInteger = Integer -> SimpleExpr
forall a b. FromIntegral a b => b -> a
fromIntegral

-- | Applies a function recursivelly until it has no effect.
-- Strict.
-- Unsafe due to possible inifinite recursion.
--
-- ==== __Examples of usage__
--
-- >>> import Prelude (Integer, div)
-- >>> iterateUntilEqual (`div` 2) (1000 :: Integer)
-- 0
iterateUntilEqual :: (Eq x) => (x -> x) -> x -> x
iterateUntilEqual :: forall x. Eq x => (x -> x) -> x -> x
iterateUntilEqual x -> x
f x
x =
  let fx :: x
fx = x -> x
f x
x
   in if x
fx x -> x -> Bool
forall a. Eq a => a -> a -> Bool
== x
x
        then x
x
        else x -> x -> x
forall a b. a -> b -> b
seq x
fx ((x -> x) -> x -> x
forall x. Eq x => (x -> x) -> x -> x
iterateUntilEqual x -> x
f x
fx)

-- | Minimalistic simplification step.
--
-- ==== __Examples of usage__
--
-- >>> import Prelude (($), id)
-- >>> import NumHask ((+), (*), (**))
--
-- >>> simplifyStep id (0 + (0 + (0 + 10)))
-- 0+(0+10)
--
-- >>> simplifyStep id (1 * (0 + (10 ** 1)))
-- 0+(10^1)
simplifyStep :: (SimpleExpr -> SimpleExpr) -> SimpleExpr -> SimpleExpr
simplifyStep :: (SimpleExpr -> SimpleExpr) -> SimpleExpr -> SimpleExpr
simplifyStep SimpleExpr -> SimpleExpr
f SimpleExpr
e = case SimpleExpr
e of
  n :: SimpleExpr
n@(Fix (NumberF Natural
_)) -> SimpleExpr
n
  c :: SimpleExpr
c@(Fix (VariableF String
_)) -> SimpleExpr
c
  Fix (SymbolicFuncF String
name [SimpleExpr
arg]) -> case String
name of
    String
"-" -> case SimpleExpr -> SimpleExprF SimpleExpr
forall (f :: * -> *). Fix f -> f (Fix f)
unFix (SimpleExpr -> SimpleExpr
f SimpleExpr
arg) of
      NumberF Natural
0 -> SimpleExprF SimpleExpr -> SimpleExpr
forall (f :: * -> *). f (Fix f) -> Fix f
Fix (SimpleExprF SimpleExpr -> SimpleExpr)
-> SimpleExprF SimpleExpr -> SimpleExpr
forall a b. (a -> b) -> a -> b
$ Natural -> SimpleExprF SimpleExpr
forall a. Natural -> SimpleExprF a
NumberF Natural
0
      SymbolicFuncF String
"-" [SimpleExpr
arg'] -> SimpleExpr -> SimpleExpr
f SimpleExpr
arg'
      SymbolicFuncF String
"(-)" [SimpleExpr
leftArg, SimpleExpr
rightArg] -> SimpleExprF SimpleExpr -> SimpleExpr
forall (f :: * -> *). f (Fix f) -> Fix f
Fix (SimpleExprF SimpleExpr -> SimpleExpr)
-> SimpleExprF SimpleExpr -> SimpleExpr
forall a b. (a -> b) -> a -> b
$ String -> [SimpleExpr] -> SimpleExprF SimpleExpr
forall a. String -> [a] -> SimpleExprF a
SymbolicFuncF String
"(-)" [SimpleExpr -> SimpleExpr
f SimpleExpr
rightArg, SimpleExpr -> SimpleExpr
f SimpleExpr
leftArg]
      SimpleExprF SimpleExpr
_ -> SimpleExprF SimpleExpr -> SimpleExpr
forall (f :: * -> *). f (Fix f) -> Fix f
Fix (SimpleExprF SimpleExpr -> SimpleExpr)
-> SimpleExprF SimpleExpr -> SimpleExpr
forall a b. (a -> b) -> a -> b
$ String -> [SimpleExpr] -> SimpleExprF SimpleExpr
forall a. String -> [a] -> SimpleExprF a
SymbolicFuncF String
"-" [SimpleExpr -> SimpleExpr
f SimpleExpr
arg]
    String
_ -> SimpleExprF SimpleExpr -> SimpleExpr
forall (f :: * -> *). f (Fix f) -> Fix f
Fix (SimpleExprF SimpleExpr -> SimpleExpr)
-> SimpleExprF SimpleExpr -> SimpleExpr
forall a b. (a -> b) -> a -> b
$ String -> [SimpleExpr] -> SimpleExprF SimpleExpr
forall a. String -> [a] -> SimpleExprF a
SymbolicFuncF String
name [SimpleExpr -> SimpleExpr
f SimpleExpr
arg]
  Fix (SymbolicFuncF String
name [SimpleExpr
leftArg, SimpleExpr
rightArg]) -> case String
name of
    String
"(+)" -> case (SimpleExpr -> SimpleExprF SimpleExpr
forall (f :: * -> *). Fix f -> f (Fix f)
unFix SimpleExpr
leftArg, SimpleExpr -> SimpleExprF SimpleExpr
forall (f :: * -> *). Fix f -> f (Fix f)
unFix SimpleExpr
rightArg) of
      (NumberF Natural
0, SimpleExprF SimpleExpr
_) -> SimpleExpr -> SimpleExpr
f SimpleExpr
rightArg
      (SimpleExprF SimpleExpr
_, NumberF Natural
0) -> SimpleExpr -> SimpleExpr
f SimpleExpr
leftArg
      (NumberF Natural
n, NumberF Natural
m) -> SimpleExprF SimpleExpr -> SimpleExpr
forall (f :: * -> *). f (Fix f) -> Fix f
Fix (Natural -> SimpleExprF SimpleExpr
forall a. Natural -> SimpleExprF a
NumberF (Natural
n Natural -> Natural -> Natural
forall a. Num a => a -> a -> a
P.+ Natural
m))
      (SimpleExprF SimpleExpr, SimpleExprF SimpleExpr)
_ -> SimpleExprF SimpleExpr -> SimpleExpr
forall (f :: * -> *). f (Fix f) -> Fix f
Fix (String -> [SimpleExpr] -> SimpleExprF SimpleExpr
forall a. String -> [a] -> SimpleExprF a
SymbolicFuncF String
"(+)" [SimpleExpr -> SimpleExpr
f SimpleExpr
leftArg, SimpleExpr -> SimpleExpr
f SimpleExpr
rightArg])
    String
"(-)" -> case (SimpleExpr -> SimpleExprF SimpleExpr
forall (f :: * -> *). Fix f -> f (Fix f)
unFix SimpleExpr
leftArg, SimpleExpr -> SimpleExprF SimpleExpr
forall (f :: * -> *). Fix f -> f (Fix f)
unFix SimpleExpr
rightArg) of
      (NumberF Natural
0, SimpleExprF SimpleExpr
_) -> (SimpleExpr -> SimpleExpr) -> SimpleExpr -> SimpleExpr
forall a. Subtractive a => a -> a
NH.negate SimpleExpr -> SimpleExpr
f SimpleExpr
rightArg
      (SimpleExprF SimpleExpr
_, NumberF Natural
0) -> SimpleExpr -> SimpleExpr
f SimpleExpr
leftArg
      (NumberF Natural
n, NumberF Natural
m) -> SimpleExprF SimpleExpr -> SimpleExpr
forall (f :: * -> *). f (Fix f) -> Fix f
Fix (Natural -> SimpleExprF SimpleExpr
forall a. Natural -> SimpleExprF a
NumberF (Natural
n Natural -> Natural -> Natural
forall a. Num a => a -> a -> a
P.- Natural
m))
      (SimpleExprF SimpleExpr, SimpleExprF SimpleExpr)
_ ->
        if SimpleExpr
fX SimpleExpr -> SimpleExpr -> Bool
forall a. Eq a => a -> a -> Bool
== SimpleExpr
fY
          then SimpleExpr
forall a. Additive a => a
zero
          else SimpleExprF SimpleExpr -> SimpleExpr
forall (f :: * -> *). f (Fix f) -> Fix f
Fix (String -> [SimpleExpr] -> SimpleExprF SimpleExpr
forall a. String -> [a] -> SimpleExprF a
SymbolicFuncF String
"(-)" [SimpleExpr
fX, SimpleExpr
fY])
        where
          fX :: SimpleExpr
fX = SimpleExpr -> SimpleExpr
f SimpleExpr
leftArg
          fY :: SimpleExpr
fY = SimpleExpr -> SimpleExpr
f SimpleExpr
rightArg
    String
"(*)" -> case (SimpleExpr -> SimpleExprF SimpleExpr
forall (f :: * -> *). Fix f -> f (Fix f)
unFix SimpleExpr
leftArg, SimpleExpr -> SimpleExprF SimpleExpr
forall (f :: * -> *). Fix f -> f (Fix f)
unFix SimpleExpr
rightArg) of
      (NumberF Natural
0, SimpleExprF SimpleExpr
_) -> SimpleExpr
forall a. Additive a => a
zero
      (SimpleExprF SimpleExpr
_, NumberF Natural
0) -> SimpleExpr
forall a. Additive a => a
zero
      (NumberF Natural
1, SimpleExprF SimpleExpr
_) -> SimpleExpr -> SimpleExpr
f SimpleExpr
rightArg
      (SimpleExprF SimpleExpr
_, NumberF Natural
1) -> SimpleExpr -> SimpleExpr
f SimpleExpr
leftArg
      (NumberF Natural
n, NumberF Natural
m) -> SimpleExprF SimpleExpr -> SimpleExpr
forall (f :: * -> *). f (Fix f) -> Fix f
Fix (Natural -> SimpleExprF SimpleExpr
forall a. Natural -> SimpleExprF a
NumberF (Natural
n Natural -> Natural -> Natural
forall a. Num a => a -> a -> a
P.* Natural
m))
      (SymbolicFuncF String
"-" [SimpleExpr
leftArg'], SymbolicFuncF String
"-" [SimpleExpr
rightArg']) ->
        SimpleExprF SimpleExpr -> SimpleExpr
forall (f :: * -> *). f (Fix f) -> Fix f
Fix (SimpleExprF SimpleExpr -> SimpleExpr)
-> SimpleExprF SimpleExpr -> SimpleExpr
forall a b. (a -> b) -> a -> b
$ String -> [SimpleExpr] -> SimpleExprF SimpleExpr
forall a. String -> [a] -> SimpleExprF a
SymbolicFuncF String
"(*)" [SimpleExpr -> SimpleExpr
f SimpleExpr
leftArg', SimpleExpr -> SimpleExpr
f SimpleExpr
rightArg']
      (SymbolicFuncF String
"-" [SimpleExpr
leftArg'], SimpleExprF SimpleExpr
rightArg') ->
        SimpleExprF SimpleExpr -> SimpleExpr
forall (f :: * -> *). f (Fix f) -> Fix f
Fix (SimpleExprF SimpleExpr -> SimpleExpr)
-> SimpleExprF SimpleExpr -> SimpleExpr
forall a b. (a -> b) -> a -> b
$ String -> [SimpleExpr] -> SimpleExprF SimpleExpr
forall a. String -> [a] -> SimpleExprF a
SymbolicFuncF String
"-" [SimpleExprF SimpleExpr -> SimpleExpr
forall (f :: * -> *). f (Fix f) -> Fix f
Fix (SimpleExprF SimpleExpr -> SimpleExpr)
-> SimpleExprF SimpleExpr -> SimpleExpr
forall a b. (a -> b) -> a -> b
$ String -> [SimpleExpr] -> SimpleExprF SimpleExpr
forall a. String -> [a] -> SimpleExprF a
SymbolicFuncF String
"(*)" [SimpleExpr
leftArg', SimpleExprF SimpleExpr -> SimpleExpr
forall (f :: * -> *). f (Fix f) -> Fix f
Fix SimpleExprF SimpleExpr
rightArg']]
      (SimpleExprF SimpleExpr
leftArg', SymbolicFuncF String
"-" [SimpleExpr
rightArg']) ->
        SimpleExprF SimpleExpr -> SimpleExpr
forall (f :: * -> *). f (Fix f) -> Fix f
Fix (SimpleExprF SimpleExpr -> SimpleExpr)
-> SimpleExprF SimpleExpr -> SimpleExpr
forall a b. (a -> b) -> a -> b
$ String -> [SimpleExpr] -> SimpleExprF SimpleExpr
forall a. String -> [a] -> SimpleExprF a
SymbolicFuncF String
"-" [SimpleExprF SimpleExpr -> SimpleExpr
forall (f :: * -> *). f (Fix f) -> Fix f
Fix (SimpleExprF SimpleExpr -> SimpleExpr)
-> SimpleExprF SimpleExpr -> SimpleExpr
forall a b. (a -> b) -> a -> b
$ String -> [SimpleExpr] -> SimpleExprF SimpleExpr
forall a. String -> [a] -> SimpleExprF a
SymbolicFuncF String
"(*)" [SimpleExprF SimpleExpr -> SimpleExpr
forall (f :: * -> *). f (Fix f) -> Fix f
Fix SimpleExprF SimpleExpr
leftArg', SimpleExpr
rightArg']]
      (SimpleExprF SimpleExpr, SimpleExprF SimpleExpr)
_ -> SimpleExprF SimpleExpr -> SimpleExpr
forall (f :: * -> *). f (Fix f) -> Fix f
Fix (String -> [SimpleExpr] -> SimpleExprF SimpleExpr
forall a. String -> [a] -> SimpleExprF a
SymbolicFuncF String
"(*)" [SimpleExpr -> SimpleExpr
f SimpleExpr
leftArg, SimpleExpr -> SimpleExpr
f SimpleExpr
rightArg])
    String
"(^)" -> case (SimpleExpr -> SimpleExprF SimpleExpr
forall (f :: * -> *). Fix f -> f (Fix f)
unFix SimpleExpr
leftArg, SimpleExpr -> SimpleExprF SimpleExpr
forall (f :: * -> *). Fix f -> f (Fix f)
unFix SimpleExpr
rightArg) of
      (NumberF Natural
n, NumberF Natural
m) -> SimpleExprF SimpleExpr -> SimpleExpr
forall (f :: * -> *). f (Fix f) -> Fix f
Fix (Natural -> SimpleExprF SimpleExpr
forall a. Natural -> SimpleExprF a
NumberF (Natural
n Natural -> Natural -> Natural
forall a b. (Num a, Integral b) => a -> b -> a
P.^ Natural
m))
      (NumberF Natural
0, SimpleExprF SimpleExpr
_) -> SimpleExpr
forall a. Additive a => a
zero
      (SimpleExprF SimpleExpr
_, NumberF Natural
0) -> SimpleExpr
forall a. Multiplicative a => a
one
      (NumberF Natural
1, SimpleExprF SimpleExpr
_) -> SimpleExpr
forall a. Multiplicative a => a
one
      (SimpleExprF SimpleExpr
_, NumberF Natural
1) -> SimpleExpr -> SimpleExpr
f SimpleExpr
leftArg
      (SimpleExprF SimpleExpr, SimpleExprF SimpleExpr)
_ -> SimpleExprF SimpleExpr -> SimpleExpr
forall (f :: * -> *). f (Fix f) -> Fix f
Fix (String -> [SimpleExpr] -> SimpleExprF SimpleExpr
forall a. String -> [a] -> SimpleExprF a
SymbolicFuncF String
"(^)" [SimpleExpr -> SimpleExpr
f SimpleExpr
leftArg, SimpleExpr -> SimpleExpr
f SimpleExpr
rightArg])
    String
_ -> SimpleExprF SimpleExpr -> SimpleExpr
forall (f :: * -> *). f (Fix f) -> Fix f
Fix (String -> [SimpleExpr] -> SimpleExprF SimpleExpr
forall a. String -> [a] -> SimpleExprF a
SymbolicFuncF String
name [SimpleExpr -> SimpleExpr
f SimpleExpr
leftArg, SimpleExpr -> SimpleExpr
f SimpleExpr
rightArg])
  Fix (SymbolicFuncF String
name [SimpleExpr]
args) -> SimpleExprF SimpleExpr -> SimpleExpr
forall (f :: * -> *). f (Fix f) -> Fix f
Fix (String -> [SimpleExpr] -> SimpleExprF SimpleExpr
forall a. String -> [a] -> SimpleExprF a
SymbolicFuncF String
name ((SimpleExpr -> SimpleExpr) -> [SimpleExpr] -> [SimpleExpr]
forall a b. (a -> b) -> [a] -> [b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap SimpleExpr -> SimpleExpr
f [SimpleExpr]
args))

-- | Simplify expression using some primitive rules
-- like '0 * x -> 0' specified in 'simplifyStep' implementation.
--
-- ==== __Examples of usage__
--
-- >>> import Prelude (($))
-- >>> import Debug.SimpleExpr (variable, simplify)
-- >>> import NumHask ((+), (-), (*))
--
-- >>> x = variable "x"
-- >>> simplifyExpr $ (x + 0) * 1 - x * (3 - 2)
-- 0
simplifyExpr :: SimpleExpr -> SimpleExpr
simplifyExpr :: SimpleExpr -> SimpleExpr
simplifyExpr = ((SimpleExpr -> SimpleExpr) -> SimpleExpr -> SimpleExpr)
-> SimpleExpr -> SimpleExpr
forall a. (a -> a) -> a
fix (((SimpleExpr -> SimpleExpr) -> SimpleExpr -> SimpleExpr)
 -> SimpleExpr -> SimpleExpr)
-> ((SimpleExpr -> SimpleExpr) -> SimpleExpr -> SimpleExpr)
-> SimpleExpr
-> SimpleExpr
forall a b. (a -> b) -> a -> b
$ (SimpleExpr -> SimpleExpr) -> SimpleExpr -> SimpleExpr
forall x. Eq x => (x -> x) -> x -> x
iterateUntilEqual ((SimpleExpr -> SimpleExpr) -> SimpleExpr -> SimpleExpr)
-> ((SimpleExpr -> SimpleExpr) -> SimpleExpr -> SimpleExpr)
-> (SimpleExpr -> SimpleExpr)
-> SimpleExpr
-> SimpleExpr
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (SimpleExpr -> SimpleExpr) -> SimpleExpr -> SimpleExpr
simplifyStep

-- | Simplify expression using some primitive rules
-- like '0 * x -> 0' specified in `simplifyStep` implementation.
simplify :: (ExtandableMap SimpleExpr SimpleExpr a a) => a -> a
simplify :: forall a. ExtandableMap SimpleExpr SimpleExpr a a => a -> a
simplify = (SimpleExpr -> SimpleExpr) -> a -> a
forall a b c d. ExtandableMap a b c d => (a -> b) -> c -> d
extendMap SimpleExpr -> SimpleExpr
simplifyExpr