{-# LANGUAGE DerivingVia #-}
{-# LANGUAGE PatternSynonyms #-}

-- |
-- Module: Symtegration.Symbolic
-- Description: Library for symbolically representing mathematical expressions.
-- Copyright: Copyright 2024 Yoo Chung
-- License: Apache-2.0
-- Maintainer: dev@chungyc.org
module Symtegration.Symbolic
  ( -- * Representation
    Expression (..),
    UnaryFunction (..),
    BinaryFunction (..),

    -- * Manipulation
    substitute,

    -- * Computation
    evaluate,
    fractionalEvaluate,
    toFunction,
    getUnaryFunction,
    getBinaryFunction,

    -- * Pattern synonyms

    -- | Pattern synonyms are defined to make it more convenient to pattern match on 'Expression'.

    -- ** Constants
    pattern Pi',

    -- ** Unary functions
    pattern Negate',
    pattern Abs',
    pattern Signum',
    pattern Exp',
    pattern Log',
    pattern Sqrt',
    pattern Sin',
    pattern Cos',
    pattern Tan',
    pattern Asin',
    pattern Acos',
    pattern Atan',
    pattern Sinh',
    pattern Cosh',
    pattern Tanh',
    pattern Asinh',
    pattern Acosh',
    pattern Atanh',

    -- ** Binary functions
    pattern (:+:),
    pattern (:*:),
    pattern (:-:),
    pattern (:/:),
    pattern (:**:),
    pattern LogBase',
  )
where

import Data.Ratio
import Data.String (IsString, fromString)
import Data.Text
import GHC.Generics (Generic)
import TextShow (TextShow)
import TextShow.Generic (FromGeneric (..))

-- $setup
-- >>> import Symtegration

-- | Symbolic representation of a mathematical expression.
-- It is an instance of the 'Num', 'Fractional', and 'Floating' type classes,
-- so normal Haskell expressions can be used, although the expressions
-- are limited to using the functions defined by these type classses.
-- The type is also an instance of the 'IsString' type class,
-- so symbols can be expressed as Haskell string with the @OverloadedStrings@ extension.
-- The structure of these values is intended to be visible.
--
-- >>> 2 :: Expression
-- Number 2
-- >>> "x" :: Expression
-- Symbol "x"
-- >>> 2 + sin "x" :: Expression
-- BinaryApply Add (Number 2) (UnaryApply Sin (Symbol "x"))
--
-- A somewhat more concise representation can be obtained using 'Symtegration.toHaskell':
--
-- >>> toHaskell $ 2 * "y" + sin "x"
-- "2 * y + sin x"
data Expression
  = -- | Represents a concrete number.
    Number Integer
  | -- | Represents a symbol, which could either be a variable or a constant.
    Symbol Text
  | -- | Represents the application of an unary function.
    UnaryApply UnaryFunction Expression
  | -- | Represents the application of a binary function.
    BinaryApply BinaryFunction Expression Expression
  deriving
    ( -- | Structural equality, not semantic equality.
      -- E.g., @"a" - "a" /= 0@.
      Expression -> Expression -> Bool
(Expression -> Expression -> Bool)
-> (Expression -> Expression -> Bool) -> Eq Expression
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Expression -> Expression -> Bool
== :: Expression -> Expression -> Bool
$c/= :: Expression -> Expression -> Bool
/= :: Expression -> Expression -> Bool
Eq,
      Int -> Expression -> ShowS
[Expression] -> ShowS
Expression -> String
(Int -> Expression -> ShowS)
-> (Expression -> String)
-> ([Expression] -> ShowS)
-> Show Expression
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Expression -> ShowS
showsPrec :: Int -> Expression -> ShowS
$cshow :: Expression -> String
show :: Expression -> String
$cshowList :: [Expression] -> ShowS
showList :: [Expression] -> ShowS
Show,
      ReadPrec [Expression]
ReadPrec Expression
Int -> ReadS Expression
ReadS [Expression]
(Int -> ReadS Expression)
-> ReadS [Expression]
-> ReadPrec Expression
-> ReadPrec [Expression]
-> Read Expression
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
$creadsPrec :: Int -> ReadS Expression
readsPrec :: Int -> ReadS Expression
$creadList :: ReadS [Expression]
readList :: ReadS [Expression]
$creadPrec :: ReadPrec Expression
readPrec :: ReadPrec Expression
$creadListPrec :: ReadPrec [Expression]
readListPrec :: ReadPrec [Expression]
Read,
      (forall x. Expression -> Rep Expression x)
-> (forall x. Rep Expression x -> Expression) -> Generic Expression
forall x. Rep Expression x -> Expression
forall x. Expression -> Rep Expression x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. Expression -> Rep Expression x
from :: forall x. Expression -> Rep Expression x
$cto :: forall x. Rep Expression x -> Expression
to :: forall x. Rep Expression x -> Expression
Generic
    )
  deriving (Int -> Expression -> Text
Int -> Expression -> Text
Int -> Expression -> Builder
[Expression] -> Text
[Expression] -> Text
[Expression] -> Builder
Expression -> Text
Expression -> Text
Expression -> Builder
(Int -> Expression -> Builder)
-> (Expression -> Builder)
-> ([Expression] -> Builder)
-> (Int -> Expression -> Text)
-> (Expression -> Text)
-> ([Expression] -> Text)
-> (Int -> Expression -> Text)
-> (Expression -> Text)
-> ([Expression] -> Text)
-> TextShow Expression
forall a.
(Int -> a -> Builder)
-> (a -> Builder)
-> ([a] -> Builder)
-> (Int -> a -> Text)
-> (a -> Text)
-> ([a] -> Text)
-> (Int -> a -> Text)
-> (a -> Text)
-> ([a] -> Text)
-> TextShow a
$cshowbPrec :: Int -> Expression -> Builder
showbPrec :: Int -> Expression -> Builder
$cshowb :: Expression -> Builder
showb :: Expression -> Builder
$cshowbList :: [Expression] -> Builder
showbList :: [Expression] -> Builder
$cshowtPrec :: Int -> Expression -> Text
showtPrec :: Int -> Expression -> Text
$cshowt :: Expression -> Text
showt :: Expression -> Text
$cshowtList :: [Expression] -> Text
showtList :: [Expression] -> Text
$cshowtlPrec :: Int -> Expression -> Text
showtlPrec :: Int -> Expression -> Text
$cshowtl :: Expression -> Text
showtl :: Expression -> Text
$cshowtlList :: [Expression] -> Text
showtlList :: [Expression] -> Text
TextShow) via FromGeneric Expression

pattern Pi' :: Expression
pattern $mPi' :: forall {r}. Expression -> ((# #) -> r) -> ((# #) -> r) -> r
$bPi' :: Expression
Pi' = Symbol "pi"

-- | Symbolic representation for unary functions.
data UnaryFunction
  = -- | 'negate'
    Negate
  | -- | 'abs'
    Abs
  | -- | 'signum'
    Signum
  | -- | 'exp'
    Exp
  | -- | 'log'
    Log
  | -- | 'sqrt'
    Sqrt
  | -- | 'sin'
    Sin
  | -- | 'cos'
    Cos
  | -- | 'tan'
    Tan
  | -- | 'asin'
    Asin
  | -- | 'acos'
    Acos
  | -- | 'atan'
    Atan
  | -- | 'sinh'
    Sinh
  | -- | 'cosh'
    Cosh
  | -- | 'tanh'
    Tanh
  | -- | 'asinh'
    Asinh
  | -- | 'acosh'
    Acosh
  | -- | 'atanh'
    Atanh
  deriving (UnaryFunction -> UnaryFunction -> Bool
(UnaryFunction -> UnaryFunction -> Bool)
-> (UnaryFunction -> UnaryFunction -> Bool) -> Eq UnaryFunction
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: UnaryFunction -> UnaryFunction -> Bool
== :: UnaryFunction -> UnaryFunction -> Bool
$c/= :: UnaryFunction -> UnaryFunction -> Bool
/= :: UnaryFunction -> UnaryFunction -> Bool
Eq, Int -> UnaryFunction
UnaryFunction -> Int
UnaryFunction -> [UnaryFunction]
UnaryFunction -> UnaryFunction
UnaryFunction -> UnaryFunction -> [UnaryFunction]
UnaryFunction -> UnaryFunction -> UnaryFunction -> [UnaryFunction]
(UnaryFunction -> UnaryFunction)
-> (UnaryFunction -> UnaryFunction)
-> (Int -> UnaryFunction)
-> (UnaryFunction -> Int)
-> (UnaryFunction -> [UnaryFunction])
-> (UnaryFunction -> UnaryFunction -> [UnaryFunction])
-> (UnaryFunction -> UnaryFunction -> [UnaryFunction])
-> (UnaryFunction
    -> UnaryFunction -> UnaryFunction -> [UnaryFunction])
-> Enum UnaryFunction
forall a.
(a -> a)
-> (a -> a)
-> (Int -> a)
-> (a -> Int)
-> (a -> [a])
-> (a -> a -> [a])
-> (a -> a -> [a])
-> (a -> a -> a -> [a])
-> Enum a
$csucc :: UnaryFunction -> UnaryFunction
succ :: UnaryFunction -> UnaryFunction
$cpred :: UnaryFunction -> UnaryFunction
pred :: UnaryFunction -> UnaryFunction
$ctoEnum :: Int -> UnaryFunction
toEnum :: Int -> UnaryFunction
$cfromEnum :: UnaryFunction -> Int
fromEnum :: UnaryFunction -> Int
$cenumFrom :: UnaryFunction -> [UnaryFunction]
enumFrom :: UnaryFunction -> [UnaryFunction]
$cenumFromThen :: UnaryFunction -> UnaryFunction -> [UnaryFunction]
enumFromThen :: UnaryFunction -> UnaryFunction -> [UnaryFunction]
$cenumFromTo :: UnaryFunction -> UnaryFunction -> [UnaryFunction]
enumFromTo :: UnaryFunction -> UnaryFunction -> [UnaryFunction]
$cenumFromThenTo :: UnaryFunction -> UnaryFunction -> UnaryFunction -> [UnaryFunction]
enumFromThenTo :: UnaryFunction -> UnaryFunction -> UnaryFunction -> [UnaryFunction]
Enum, UnaryFunction
UnaryFunction -> UnaryFunction -> Bounded UnaryFunction
forall a. a -> a -> Bounded a
$cminBound :: UnaryFunction
minBound :: UnaryFunction
$cmaxBound :: UnaryFunction
maxBound :: UnaryFunction
Bounded, Int -> UnaryFunction -> ShowS
[UnaryFunction] -> ShowS
UnaryFunction -> String
(Int -> UnaryFunction -> ShowS)
-> (UnaryFunction -> String)
-> ([UnaryFunction] -> ShowS)
-> Show UnaryFunction
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> UnaryFunction -> ShowS
showsPrec :: Int -> UnaryFunction -> ShowS
$cshow :: UnaryFunction -> String
show :: UnaryFunction -> String
$cshowList :: [UnaryFunction] -> ShowS
showList :: [UnaryFunction] -> ShowS
Show, ReadPrec [UnaryFunction]
ReadPrec UnaryFunction
Int -> ReadS UnaryFunction
ReadS [UnaryFunction]
(Int -> ReadS UnaryFunction)
-> ReadS [UnaryFunction]
-> ReadPrec UnaryFunction
-> ReadPrec [UnaryFunction]
-> Read UnaryFunction
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
$creadsPrec :: Int -> ReadS UnaryFunction
readsPrec :: Int -> ReadS UnaryFunction
$creadList :: ReadS [UnaryFunction]
readList :: ReadS [UnaryFunction]
$creadPrec :: ReadPrec UnaryFunction
readPrec :: ReadPrec UnaryFunction
$creadListPrec :: ReadPrec [UnaryFunction]
readListPrec :: ReadPrec [UnaryFunction]
Read, (forall x. UnaryFunction -> Rep UnaryFunction x)
-> (forall x. Rep UnaryFunction x -> UnaryFunction)
-> Generic UnaryFunction
forall x. Rep UnaryFunction x -> UnaryFunction
forall x. UnaryFunction -> Rep UnaryFunction x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. UnaryFunction -> Rep UnaryFunction x
from :: forall x. UnaryFunction -> Rep UnaryFunction x
$cto :: forall x. Rep UnaryFunction x -> UnaryFunction
to :: forall x. Rep UnaryFunction x -> UnaryFunction
Generic)
  deriving (Int -> UnaryFunction -> Text
Int -> UnaryFunction -> Text
Int -> UnaryFunction -> Builder
[UnaryFunction] -> Text
[UnaryFunction] -> Text
[UnaryFunction] -> Builder
UnaryFunction -> Text
UnaryFunction -> Text
UnaryFunction -> Builder
(Int -> UnaryFunction -> Builder)
-> (UnaryFunction -> Builder)
-> ([UnaryFunction] -> Builder)
-> (Int -> UnaryFunction -> Text)
-> (UnaryFunction -> Text)
-> ([UnaryFunction] -> Text)
-> (Int -> UnaryFunction -> Text)
-> (UnaryFunction -> Text)
-> ([UnaryFunction] -> Text)
-> TextShow UnaryFunction
forall a.
(Int -> a -> Builder)
-> (a -> Builder)
-> ([a] -> Builder)
-> (Int -> a -> Text)
-> (a -> Text)
-> ([a] -> Text)
-> (Int -> a -> Text)
-> (a -> Text)
-> ([a] -> Text)
-> TextShow a
$cshowbPrec :: Int -> UnaryFunction -> Builder
showbPrec :: Int -> UnaryFunction -> Builder
$cshowb :: UnaryFunction -> Builder
showb :: UnaryFunction -> Builder
$cshowbList :: [UnaryFunction] -> Builder
showbList :: [UnaryFunction] -> Builder
$cshowtPrec :: Int -> UnaryFunction -> Text
showtPrec :: Int -> UnaryFunction -> Text
$cshowt :: UnaryFunction -> Text
showt :: UnaryFunction -> Text
$cshowtList :: [UnaryFunction] -> Text
showtList :: [UnaryFunction] -> Text
$cshowtlPrec :: Int -> UnaryFunction -> Text
showtlPrec :: Int -> UnaryFunction -> Text
$cshowtl :: UnaryFunction -> Text
showtl :: UnaryFunction -> Text
$cshowtlList :: [UnaryFunction] -> Text
showtlList :: [UnaryFunction] -> Text
TextShow) via FromGeneric UnaryFunction

pattern Negate', Abs', Signum', Exp', Log', Sqrt', Sin', Cos', Tan', Asin', Acos', Atan', Sinh', Cosh', Tanh', Asinh', Acosh', Atanh' :: Expression -> Expression
pattern $mNegate' :: forall {r}. Expression -> (Expression -> r) -> ((# #) -> r) -> r
$bNegate' :: Expression -> Expression
Negate' x = UnaryApply Negate x
pattern $mAbs' :: forall {r}. Expression -> (Expression -> r) -> ((# #) -> r) -> r
$bAbs' :: Expression -> Expression
Abs' x = UnaryApply Abs x
pattern $mSignum' :: forall {r}. Expression -> (Expression -> r) -> ((# #) -> r) -> r
$bSignum' :: Expression -> Expression
Signum' x = UnaryApply Signum x
pattern $mExp' :: forall {r}. Expression -> (Expression -> r) -> ((# #) -> r) -> r
$bExp' :: Expression -> Expression
Exp' x = UnaryApply Exp x
pattern $mLog' :: forall {r}. Expression -> (Expression -> r) -> ((# #) -> r) -> r
$bLog' :: Expression -> Expression
Log' x = UnaryApply Log x
pattern $mSqrt' :: forall {r}. Expression -> (Expression -> r) -> ((# #) -> r) -> r
$bSqrt' :: Expression -> Expression
Sqrt' x = UnaryApply Sqrt x
pattern $mSin' :: forall {r}. Expression -> (Expression -> r) -> ((# #) -> r) -> r
$bSin' :: Expression -> Expression
Sin' x = UnaryApply Sin x
pattern $mCos' :: forall {r}. Expression -> (Expression -> r) -> ((# #) -> r) -> r
$bCos' :: Expression -> Expression
Cos' x = UnaryApply Cos x
pattern $mTan' :: forall {r}. Expression -> (Expression -> r) -> ((# #) -> r) -> r
$bTan' :: Expression -> Expression
Tan' x = UnaryApply Tan x
pattern $mAsin' :: forall {r}. Expression -> (Expression -> r) -> ((# #) -> r) -> r
$bAsin' :: Expression -> Expression
Asin' x = UnaryApply Asin x
pattern $mAcos' :: forall {r}. Expression -> (Expression -> r) -> ((# #) -> r) -> r
$bAcos' :: Expression -> Expression
Acos' x = UnaryApply Acos x
pattern $mAtan' :: forall {r}. Expression -> (Expression -> r) -> ((# #) -> r) -> r
$bAtan' :: Expression -> Expression
Atan' x = UnaryApply Atan x
pattern $mSinh' :: forall {r}. Expression -> (Expression -> r) -> ((# #) -> r) -> r
$bSinh' :: Expression -> Expression
Sinh' x = UnaryApply Sinh x
pattern $mCosh' :: forall {r}. Expression -> (Expression -> r) -> ((# #) -> r) -> r
$bCosh' :: Expression -> Expression
Cosh' x = UnaryApply Cosh x
pattern $mTanh' :: forall {r}. Expression -> (Expression -> r) -> ((# #) -> r) -> r
$bTanh' :: Expression -> Expression
Tanh' x = UnaryApply Tanh x
pattern $mAsinh' :: forall {r}. Expression -> (Expression -> r) -> ((# #) -> r) -> r
$bAsinh' :: Expression -> Expression
Asinh' x = UnaryApply Asinh x
pattern $mAcosh' :: forall {r}. Expression -> (Expression -> r) -> ((# #) -> r) -> r
$bAcosh' :: Expression -> Expression
Acosh' x = UnaryApply Acosh x
pattern $mAtanh' :: forall {r}. Expression -> (Expression -> r) -> ((# #) -> r) -> r
$bAtanh' :: Expression -> Expression
Atanh' x = UnaryApply Atanh x

-- | Symbolic representation for binary functions.
data BinaryFunction
  = -- | '(+)'
    Add
  | -- | '(*)'
    Multiply
  | -- | '(-)'
    Subtract
  | -- | '(/)'
    Divide
  | -- | '(**)'
    Power
  | -- | 'logBase'
    LogBase
  deriving (BinaryFunction -> BinaryFunction -> Bool
(BinaryFunction -> BinaryFunction -> Bool)
-> (BinaryFunction -> BinaryFunction -> Bool) -> Eq BinaryFunction
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: BinaryFunction -> BinaryFunction -> Bool
== :: BinaryFunction -> BinaryFunction -> Bool
$c/= :: BinaryFunction -> BinaryFunction -> Bool
/= :: BinaryFunction -> BinaryFunction -> Bool
Eq, Int -> BinaryFunction
BinaryFunction -> Int
BinaryFunction -> [BinaryFunction]
BinaryFunction -> BinaryFunction
BinaryFunction -> BinaryFunction -> [BinaryFunction]
BinaryFunction
-> BinaryFunction -> BinaryFunction -> [BinaryFunction]
(BinaryFunction -> BinaryFunction)
-> (BinaryFunction -> BinaryFunction)
-> (Int -> BinaryFunction)
-> (BinaryFunction -> Int)
-> (BinaryFunction -> [BinaryFunction])
-> (BinaryFunction -> BinaryFunction -> [BinaryFunction])
-> (BinaryFunction -> BinaryFunction -> [BinaryFunction])
-> (BinaryFunction
    -> BinaryFunction -> BinaryFunction -> [BinaryFunction])
-> Enum BinaryFunction
forall a.
(a -> a)
-> (a -> a)
-> (Int -> a)
-> (a -> Int)
-> (a -> [a])
-> (a -> a -> [a])
-> (a -> a -> [a])
-> (a -> a -> a -> [a])
-> Enum a
$csucc :: BinaryFunction -> BinaryFunction
succ :: BinaryFunction -> BinaryFunction
$cpred :: BinaryFunction -> BinaryFunction
pred :: BinaryFunction -> BinaryFunction
$ctoEnum :: Int -> BinaryFunction
toEnum :: Int -> BinaryFunction
$cfromEnum :: BinaryFunction -> Int
fromEnum :: BinaryFunction -> Int
$cenumFrom :: BinaryFunction -> [BinaryFunction]
enumFrom :: BinaryFunction -> [BinaryFunction]
$cenumFromThen :: BinaryFunction -> BinaryFunction -> [BinaryFunction]
enumFromThen :: BinaryFunction -> BinaryFunction -> [BinaryFunction]
$cenumFromTo :: BinaryFunction -> BinaryFunction -> [BinaryFunction]
enumFromTo :: BinaryFunction -> BinaryFunction -> [BinaryFunction]
$cenumFromThenTo :: BinaryFunction
-> BinaryFunction -> BinaryFunction -> [BinaryFunction]
enumFromThenTo :: BinaryFunction
-> BinaryFunction -> BinaryFunction -> [BinaryFunction]
Enum, BinaryFunction
BinaryFunction -> BinaryFunction -> Bounded BinaryFunction
forall a. a -> a -> Bounded a
$cminBound :: BinaryFunction
minBound :: BinaryFunction
$cmaxBound :: BinaryFunction
maxBound :: BinaryFunction
Bounded, Int -> BinaryFunction -> ShowS
[BinaryFunction] -> ShowS
BinaryFunction -> String
(Int -> BinaryFunction -> ShowS)
-> (BinaryFunction -> String)
-> ([BinaryFunction] -> ShowS)
-> Show BinaryFunction
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> BinaryFunction -> ShowS
showsPrec :: Int -> BinaryFunction -> ShowS
$cshow :: BinaryFunction -> String
show :: BinaryFunction -> String
$cshowList :: [BinaryFunction] -> ShowS
showList :: [BinaryFunction] -> ShowS
Show, ReadPrec [BinaryFunction]
ReadPrec BinaryFunction
Int -> ReadS BinaryFunction
ReadS [BinaryFunction]
(Int -> ReadS BinaryFunction)
-> ReadS [BinaryFunction]
-> ReadPrec BinaryFunction
-> ReadPrec [BinaryFunction]
-> Read BinaryFunction
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
$creadsPrec :: Int -> ReadS BinaryFunction
readsPrec :: Int -> ReadS BinaryFunction
$creadList :: ReadS [BinaryFunction]
readList :: ReadS [BinaryFunction]
$creadPrec :: ReadPrec BinaryFunction
readPrec :: ReadPrec BinaryFunction
$creadListPrec :: ReadPrec [BinaryFunction]
readListPrec :: ReadPrec [BinaryFunction]
Read, (forall x. BinaryFunction -> Rep BinaryFunction x)
-> (forall x. Rep BinaryFunction x -> BinaryFunction)
-> Generic BinaryFunction
forall x. Rep BinaryFunction x -> BinaryFunction
forall x. BinaryFunction -> Rep BinaryFunction x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. BinaryFunction -> Rep BinaryFunction x
from :: forall x. BinaryFunction -> Rep BinaryFunction x
$cto :: forall x. Rep BinaryFunction x -> BinaryFunction
to :: forall x. Rep BinaryFunction x -> BinaryFunction
Generic)
  deriving (Int -> BinaryFunction -> Text
Int -> BinaryFunction -> Text
Int -> BinaryFunction -> Builder
[BinaryFunction] -> Text
[BinaryFunction] -> Text
[BinaryFunction] -> Builder
BinaryFunction -> Text
BinaryFunction -> Text
BinaryFunction -> Builder
(Int -> BinaryFunction -> Builder)
-> (BinaryFunction -> Builder)
-> ([BinaryFunction] -> Builder)
-> (Int -> BinaryFunction -> Text)
-> (BinaryFunction -> Text)
-> ([BinaryFunction] -> Text)
-> (Int -> BinaryFunction -> Text)
-> (BinaryFunction -> Text)
-> ([BinaryFunction] -> Text)
-> TextShow BinaryFunction
forall a.
(Int -> a -> Builder)
-> (a -> Builder)
-> ([a] -> Builder)
-> (Int -> a -> Text)
-> (a -> Text)
-> ([a] -> Text)
-> (Int -> a -> Text)
-> (a -> Text)
-> ([a] -> Text)
-> TextShow a
$cshowbPrec :: Int -> BinaryFunction -> Builder
showbPrec :: Int -> BinaryFunction -> Builder
$cshowb :: BinaryFunction -> Builder
showb :: BinaryFunction -> Builder
$cshowbList :: [BinaryFunction] -> Builder
showbList :: [BinaryFunction] -> Builder
$cshowtPrec :: Int -> BinaryFunction -> Text
showtPrec :: Int -> BinaryFunction -> Text
$cshowt :: BinaryFunction -> Text
showt :: BinaryFunction -> Text
$cshowtList :: [BinaryFunction] -> Text
showtList :: [BinaryFunction] -> Text
$cshowtlPrec :: Int -> BinaryFunction -> Text
showtlPrec :: Int -> BinaryFunction -> Text
$cshowtl :: BinaryFunction -> Text
showtl :: BinaryFunction -> Text
$cshowtlList :: [BinaryFunction] -> Text
showtlList :: [BinaryFunction] -> Text
TextShow) via FromGeneric BinaryFunction

pattern (:+:), (:*:), (:-:), (:/:), (:**:), LogBase' :: Expression -> Expression -> Expression
pattern x $m:+: :: forall {r}.
Expression -> (Expression -> Expression -> r) -> ((# #) -> r) -> r
$b:+: :: Expression -> Expression -> Expression
:+: y = BinaryApply Add x y
pattern x $m:*: :: forall {r}.
Expression -> (Expression -> Expression -> r) -> ((# #) -> r) -> r
$b:*: :: Expression -> Expression -> Expression
:*: y = BinaryApply Multiply x y
pattern x $m:-: :: forall {r}.
Expression -> (Expression -> Expression -> r) -> ((# #) -> r) -> r
$b:-: :: Expression -> Expression -> Expression
:-: y = BinaryApply Subtract x y
pattern x $m:/: :: forall {r}.
Expression -> (Expression -> Expression -> r) -> ((# #) -> r) -> r
$b:/: :: Expression -> Expression -> Expression
:/: y = BinaryApply Divide x y
pattern x $m:**: :: forall {r}.
Expression -> (Expression -> Expression -> r) -> ((# #) -> r) -> r
$b:**: :: Expression -> Expression -> Expression
:**: y = BinaryApply Power x y
pattern $mLogBase' :: forall {r}.
Expression -> (Expression -> Expression -> r) -> ((# #) -> r) -> r
$bLogBase' :: Expression -> Expression -> Expression
LogBase' x y = BinaryApply LogBase x y

instance IsString Expression where
  fromString :: String -> Expression
fromString = Text -> Expression
Symbol (Text -> Expression) -> (String -> Text) -> String -> Expression
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Text
forall a. IsString a => String -> a
fromString

instance Num Expression where
  + :: Expression -> Expression -> Expression
(+) = BinaryFunction -> Expression -> Expression -> Expression
BinaryApply BinaryFunction
Add
  (-) = BinaryFunction -> Expression -> Expression -> Expression
BinaryApply BinaryFunction
Subtract
  * :: Expression -> Expression -> Expression
(*) = BinaryFunction -> Expression -> Expression -> Expression
BinaryApply BinaryFunction
Multiply
  negate :: Expression -> Expression
negate = UnaryFunction -> Expression -> Expression
UnaryApply UnaryFunction
Negate
  abs :: Expression -> Expression
abs = UnaryFunction -> Expression -> Expression
UnaryApply UnaryFunction
Abs
  signum :: Expression -> Expression
signum = UnaryFunction -> Expression -> Expression
UnaryApply UnaryFunction
Signum
  fromInteger :: Integer -> Expression
fromInteger = Integer -> Expression
Number

instance Fractional Expression where
  / :: Expression -> Expression -> Expression
(/) = BinaryFunction -> Expression -> Expression -> Expression
BinaryApply BinaryFunction
Divide
  fromRational :: Rational -> Expression
fromRational Rational
q | Expression
d Expression -> Expression -> Bool
forall a. Eq a => a -> a -> Bool
== Expression
1 = Expression
n | Bool
otherwise = BinaryFunction -> Expression -> Expression -> Expression
BinaryApply BinaryFunction
Divide Expression
n Expression
d
    where
      n :: Expression
n = Integer -> Expression
Number (Integer -> Expression) -> Integer -> Expression
forall a b. (a -> b) -> a -> b
$ Rational -> Integer
forall a. Ratio a -> a
numerator Rational
q
      d :: Expression
d = Integer -> Expression
Number (Integer -> Expression) -> Integer -> Expression
forall a b. (a -> b) -> a -> b
$ Rational -> Integer
forall a. Ratio a -> a
denominator Rational
q

instance Floating Expression where
  pi :: Expression
pi = Text -> Expression
Symbol Text
"pi"
  exp :: Expression -> Expression
exp = UnaryFunction -> Expression -> Expression
UnaryApply UnaryFunction
Exp
  log :: Expression -> Expression
log = UnaryFunction -> Expression -> Expression
UnaryApply UnaryFunction
Log
  sqrt :: Expression -> Expression
sqrt = UnaryFunction -> Expression -> Expression
UnaryApply UnaryFunction
Sqrt
  ** :: Expression -> Expression -> Expression
(**) = BinaryFunction -> Expression -> Expression -> Expression
BinaryApply BinaryFunction
Power
  logBase :: Expression -> Expression -> Expression
logBase = BinaryFunction -> Expression -> Expression -> Expression
BinaryApply BinaryFunction
LogBase
  sin :: Expression -> Expression
sin = UnaryFunction -> Expression -> Expression
UnaryApply UnaryFunction
Sin
  cos :: Expression -> Expression
cos = UnaryFunction -> Expression -> Expression
UnaryApply UnaryFunction
Cos
  tan :: Expression -> Expression
tan = UnaryFunction -> Expression -> Expression
UnaryApply UnaryFunction
Tan
  asin :: Expression -> Expression
asin = UnaryFunction -> Expression -> Expression
UnaryApply UnaryFunction
Asin
  acos :: Expression -> Expression
acos = UnaryFunction -> Expression -> Expression
UnaryApply UnaryFunction
Acos
  atan :: Expression -> Expression
atan = UnaryFunction -> Expression -> Expression
UnaryApply UnaryFunction
Atan
  sinh :: Expression -> Expression
sinh = UnaryFunction -> Expression -> Expression
UnaryApply UnaryFunction
Sinh
  cosh :: Expression -> Expression
cosh = UnaryFunction -> Expression -> Expression
UnaryApply UnaryFunction
Cosh
  tanh :: Expression -> Expression
tanh = UnaryFunction -> Expression -> Expression
UnaryApply UnaryFunction
Tanh
  asinh :: Expression -> Expression
asinh = UnaryFunction -> Expression -> Expression
UnaryApply UnaryFunction
Asinh
  acosh :: Expression -> Expression
acosh = UnaryFunction -> Expression -> Expression
UnaryApply UnaryFunction
Acosh
  atanh :: Expression -> Expression
atanh = UnaryFunction -> Expression -> Expression
UnaryApply UnaryFunction
Atanh

-- | Returns a function corresponding to the symbolic representation of an unary function.
--
-- >>> (getUnaryFunction Cos) pi == (cos pi :: Double)
-- True
getUnaryFunction :: (Floating a) => UnaryFunction -> (a -> a)
getUnaryFunction :: forall a. Floating a => UnaryFunction -> a -> a
getUnaryFunction UnaryFunction
Negate = a -> a
forall a. Num a => a -> a
negate
getUnaryFunction UnaryFunction
Abs = a -> a
forall a. Num a => a -> a
abs
getUnaryFunction UnaryFunction
Signum = a -> a
forall a. Num a => a -> a
signum
getUnaryFunction UnaryFunction
Exp = a -> a
forall a. Floating a => a -> a
exp
getUnaryFunction UnaryFunction
Log = a -> a
forall a. Floating a => a -> a
log
getUnaryFunction UnaryFunction
Sqrt = a -> a
forall a. Floating a => a -> a
sqrt
getUnaryFunction UnaryFunction
Sin = a -> a
forall a. Floating a => a -> a
sin
getUnaryFunction UnaryFunction
Cos = a -> a
forall a. Floating a => a -> a
cos
getUnaryFunction UnaryFunction
Tan = a -> a
forall a. Floating a => a -> a
tan
getUnaryFunction UnaryFunction
Asin = a -> a
forall a. Floating a => a -> a
asin
getUnaryFunction UnaryFunction
Acos = a -> a
forall a. Floating a => a -> a
acos
getUnaryFunction UnaryFunction
Atan = a -> a
forall a. Floating a => a -> a
atan
getUnaryFunction UnaryFunction
Sinh = a -> a
forall a. Floating a => a -> a
sinh
getUnaryFunction UnaryFunction
Cosh = a -> a
forall a. Floating a => a -> a
cosh
getUnaryFunction UnaryFunction
Tanh = a -> a
forall a. Floating a => a -> a
tanh
getUnaryFunction UnaryFunction
Asinh = a -> a
forall a. Floating a => a -> a
asinh
getUnaryFunction UnaryFunction
Acosh = a -> a
forall a. Floating a => a -> a
acosh
getUnaryFunction UnaryFunction
Atanh = a -> a
forall a. Floating a => a -> a
atanh

-- | Returns a function corresponding to the symbolic representation of a binary function.
--
-- >>> (getBinaryFunction Add) 2 5 == (2 + 5 :: Double)
-- True
getBinaryFunction :: (Floating a) => BinaryFunction -> (a -> a -> a)
getBinaryFunction :: forall a. Floating a => BinaryFunction -> a -> a -> a
getBinaryFunction BinaryFunction
Add = a -> a -> a
forall a. Num a => a -> a -> a
(+)
getBinaryFunction BinaryFunction
Multiply = a -> a -> a
forall a. Num a => a -> a -> a
(*)
getBinaryFunction BinaryFunction
Subtract = (-)
getBinaryFunction BinaryFunction
Divide = a -> a -> a
forall a. Fractional a => a -> a -> a
(/)
getBinaryFunction BinaryFunction
Power = a -> a -> a
forall a. Floating a => a -> a -> a
(**)
getBinaryFunction BinaryFunction
LogBase = a -> a -> a
forall a. Floating a => a -> a -> a
logBase

-- | Substitute the symbols with the corresponding expressions they are mapped to.
-- The symbols will be replaced as is; there is no special treatment if the
-- expression they are replaced by also contains the same symbol.
--
-- >>> toHaskell $ substitute ("x" + "y") (\case "x" -> Just ("a" * "b"); "y" -> Just 4)
-- "a * b + 4"
substitute ::
  -- | Expression to apply substitution.
  Expression ->
  -- | Maps symbols to expressions they are to be substituted with.
  (Text -> Maybe Expression) ->
  -- | Expression with substitution applied.
  Expression
substitute :: Expression -> (Text -> Maybe Expression) -> Expression
substitute e :: Expression
e@(Number Integer
_) Text -> Maybe Expression
_ = Expression
e
substitute e :: Expression
e@(Symbol Text
s) Text -> Maybe Expression
f
  | (Just Expression
x) <- Text -> Maybe Expression
f Text
s = Expression
x
  | Bool
otherwise = Expression
e
substitute (UnaryApply UnaryFunction
func Expression
x) Text -> Maybe Expression
f = UnaryFunction -> Expression -> Expression
UnaryApply UnaryFunction
func (Expression -> (Text -> Maybe Expression) -> Expression
substitute Expression
x Text -> Maybe Expression
f)
substitute (BinaryApply BinaryFunction
func Expression
x Expression
y) Text -> Maybe Expression
f = BinaryFunction -> Expression -> Expression -> Expression
BinaryApply BinaryFunction
func (Expression -> (Text -> Maybe Expression) -> Expression
substitute Expression
x Text -> Maybe Expression
f) (Expression -> (Text -> Maybe Expression) -> Expression
substitute Expression
y Text -> Maybe Expression
f)

-- | Calculates the value for a mathematical expression for a given assignment of values to symbols.
--
-- For example, when \(x=5\), then \(2x+1=11\).
--
-- >>> evaluate (2 * "x" + 1) (\case "x" -> Just 5)
-- Just 11.0
--
-- All symbols except for @"pi"@ in a mathematical expression must be assigned a value.
-- Otherwise, a value cannot be computed.
--
-- >>> evaluate (2 * "x" + 1) (const Nothing)
-- Nothing
--
-- The symbol @"pi"@ is always used to represent \(\pi\),
-- and any assignment to @"pi"@ will be ignored.
-- For example, the following is \(\pi - \pi\), not \(100 - \pi\).
--
-- >>> evaluate ("pi" - pi) (\case "x" -> Just 100)
-- Just 0.0
evaluate ::
  (Floating a) =>
  -- | Mathematical expression to evaluate.
  Expression ->
  -- | Maps symbols to concrete values.
  (Text -> Maybe a) ->
  -- | Evaluation result.
  Maybe a
evaluate :: forall a. Floating a => Expression -> (Text -> Maybe a) -> Maybe a
evaluate (Number Integer
n) Text -> Maybe a
_ = a -> Maybe a
forall a. a -> Maybe a
Just (a -> Maybe a) -> a -> Maybe a
forall a b. (a -> b) -> a -> b
$ Integer -> a
forall a. Num a => Integer -> a
fromInteger Integer
n
evaluate (Symbol Text
"pi") Text -> Maybe a
_ = a -> Maybe a
forall a. a -> Maybe a
Just a
forall a. Floating a => a
pi
evaluate (Symbol Text
x) Text -> Maybe a
m = Text -> Maybe a
m Text
x
evaluate (UnaryApply UnaryFunction
fun Expression
expr) Text -> Maybe a
m = (a -> a) -> Maybe a -> Maybe a
forall a b. (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap a -> a
f Maybe a
v
  where
    f :: a -> a
f = UnaryFunction -> a -> a
forall a. Floating a => UnaryFunction -> a -> a
getUnaryFunction UnaryFunction
fun
    v :: Maybe a
v = Expression -> (Text -> Maybe a) -> Maybe a
forall a. Floating a => Expression -> (Text -> Maybe a) -> Maybe a
evaluate Expression
expr Text -> Maybe a
m
evaluate (BinaryApply BinaryFunction
fun Expression
expr1 Expression
expr2) Text -> Maybe a
m = a -> a -> a
f (a -> a -> a) -> Maybe a -> Maybe (a -> a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Maybe a
v1 Maybe (a -> a) -> Maybe a -> Maybe a
forall a b. Maybe (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Maybe a
v2
  where
    f :: a -> a -> a
f = BinaryFunction -> a -> a -> a
forall a. Floating a => BinaryFunction -> a -> a -> a
getBinaryFunction BinaryFunction
fun
    v1 :: Maybe a
v1 = Expression -> (Text -> Maybe a) -> Maybe a
forall a. Floating a => Expression -> (Text -> Maybe a) -> Maybe a
evaluate Expression
expr1 Text -> Maybe a
m
    v2 :: Maybe a
v2 = Expression -> (Text -> Maybe a) -> Maybe a
forall a. Floating a => Expression -> (Text -> Maybe a) -> Maybe a
evaluate Expression
expr2 Text -> Maybe a
m

-- |
-- Evaluates a mathematical expression with only operations available to 'Fractional' values.
-- In particular, this allows exact evaluations with 'Rational' values.
-- 'Nothing' will be returned if a function not supported by all 'Fractional' values
-- is used by the mathematical expression.
--
-- As an exception, the '(**)' operator is allowed with constant integer exponents,
-- even though '(**)' is not a function applicable to all 'Fractional' types.
--
-- For example,
--
-- >>> let p = 1 / (3 * "x"**5 - 2 * "x" + 1) :: Expression
-- >>> fractionalEvaluate p (\case "x" -> Just (2 / 7 :: Rational))
-- Just (16807 % 7299)
--
-- Compare against 'evaluate', which cannot even use 'Rational' computations
-- because 'Rational' is not an instance of the 'Floating' type class:
--
-- >>> evaluate p (\case "x" -> Just (2 / 7 :: Double))
-- Just 2.3026441978353196
fractionalEvaluate ::
  (Eq a, Fractional a) =>
  -- | Mathematical expression to evaluate.
  Expression ->
  -- | Maps symbols to concrete values.
  (Text -> Maybe a) ->
  -- | Evaluation result.
  Maybe a
fractionalEvaluate :: forall a.
(Eq a, Fractional a) =>
Expression -> (Text -> Maybe a) -> Maybe a
fractionalEvaluate (Number Integer
n) Text -> Maybe a
_ = a -> Maybe a
forall a. a -> Maybe a
Just (a -> Maybe a) -> a -> Maybe a
forall a b. (a -> b) -> a -> b
$ Integer -> a
forall a. Num a => Integer -> a
fromInteger Integer
n
fractionalEvaluate (Symbol Text
x) Text -> Maybe a
m = Text -> Maybe a
m Text
x
fractionalEvaluate (Negate' Expression
x) Text -> Maybe a
m = a -> a
forall a. Num a => a -> a
negate (a -> a) -> Maybe a -> Maybe a
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Expression -> (Text -> Maybe a) -> Maybe a
forall a.
(Eq a, Fractional a) =>
Expression -> (Text -> Maybe a) -> Maybe a
fractionalEvaluate Expression
x Text -> Maybe a
m
fractionalEvaluate (Abs' Expression
x) Text -> Maybe a
m = a -> a
forall a. Num a => a -> a
abs (a -> a) -> Maybe a -> Maybe a
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Expression -> (Text -> Maybe a) -> Maybe a
forall a.
(Eq a, Fractional a) =>
Expression -> (Text -> Maybe a) -> Maybe a
fractionalEvaluate Expression
x Text -> Maybe a
m
fractionalEvaluate (Signum' Expression
x) Text -> Maybe a
m = a -> a
forall a. Num a => a -> a
signum (a -> a) -> Maybe a -> Maybe a
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Expression -> (Text -> Maybe a) -> Maybe a
forall a.
(Eq a, Fractional a) =>
Expression -> (Text -> Maybe a) -> Maybe a
fractionalEvaluate Expression
x Text -> Maybe a
m
fractionalEvaluate (Expression
x :+: Expression
y) Text -> Maybe a
m = a -> a -> a
forall a. Num a => a -> a -> a
(+) (a -> a -> a) -> Maybe a -> Maybe (a -> a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Expression -> (Text -> Maybe a) -> Maybe a
forall a.
(Eq a, Fractional a) =>
Expression -> (Text -> Maybe a) -> Maybe a
fractionalEvaluate Expression
x Text -> Maybe a
m Maybe (a -> a) -> Maybe a -> Maybe a
forall a b. Maybe (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Expression -> (Text -> Maybe a) -> Maybe a
forall a.
(Eq a, Fractional a) =>
Expression -> (Text -> Maybe a) -> Maybe a
fractionalEvaluate Expression
y Text -> Maybe a
m
fractionalEvaluate (Expression
x :-: Expression
y) Text -> Maybe a
m = (-) (a -> a -> a) -> Maybe a -> Maybe (a -> a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Expression -> (Text -> Maybe a) -> Maybe a
forall a.
(Eq a, Fractional a) =>
Expression -> (Text -> Maybe a) -> Maybe a
fractionalEvaluate Expression
x Text -> Maybe a
m Maybe (a -> a) -> Maybe a -> Maybe a
forall a b. Maybe (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Expression -> (Text -> Maybe a) -> Maybe a
forall a.
(Eq a, Fractional a) =>
Expression -> (Text -> Maybe a) -> Maybe a
fractionalEvaluate Expression
y Text -> Maybe a
m
fractionalEvaluate (Expression
x :*: Expression
y) Text -> Maybe a
m = a -> a -> a
forall a. Num a => a -> a -> a
(*) (a -> a -> a) -> Maybe a -> Maybe (a -> a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Expression -> (Text -> Maybe a) -> Maybe a
forall a.
(Eq a, Fractional a) =>
Expression -> (Text -> Maybe a) -> Maybe a
fractionalEvaluate Expression
x Text -> Maybe a
m Maybe (a -> a) -> Maybe a -> Maybe a
forall a b. Maybe (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Expression -> (Text -> Maybe a) -> Maybe a
forall a.
(Eq a, Fractional a) =>
Expression -> (Text -> Maybe a) -> Maybe a
fractionalEvaluate Expression
y Text -> Maybe a
m
fractionalEvaluate (Expression
x :/: Expression
y) Text -> Maybe a
m
  | Just a
0 <- Maybe a
y' = Maybe a
forall a. Maybe a
Nothing
  | Bool
otherwise = a -> a -> a
forall a. Fractional a => a -> a -> a
(/) (a -> a -> a) -> Maybe a -> Maybe (a -> a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Maybe a
x' Maybe (a -> a) -> Maybe a -> Maybe a
forall a b. Maybe (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Maybe a
y'
  where
    x' :: Maybe a
x' = Expression -> (Text -> Maybe a) -> Maybe a
forall a.
(Eq a, Fractional a) =>
Expression -> (Text -> Maybe a) -> Maybe a
fractionalEvaluate Expression
x Text -> Maybe a
m
    y' :: Maybe a
y' = Expression -> (Text -> Maybe a) -> Maybe a
forall a.
(Eq a, Fractional a) =>
Expression -> (Text -> Maybe a) -> Maybe a
fractionalEvaluate Expression
y Text -> Maybe a
m
fractionalEvaluate (Expression
x :**: (Number Integer
n)) Text -> Maybe a
m = (a -> Integer -> a
forall a b. (Fractional a, Integral b) => a -> b -> a
^^ Integer
n) (a -> a) -> Maybe a -> Maybe a
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Expression -> (Text -> Maybe a) -> Maybe a
forall a.
(Eq a, Fractional a) =>
Expression -> (Text -> Maybe a) -> Maybe a
fractionalEvaluate Expression
x Text -> Maybe a
m
fractionalEvaluate Expression
_ Text -> Maybe a
_ = Maybe a
forall a. Maybe a
Nothing

-- | Returns a function based on a given expression.  This requires
-- a specification of how a symbol maps the argument to a value
-- to be used in its place.
--
-- For example, the symbol "x" could use the argument as is as its value.
-- I.e., "x" can be mapped to a function which maps the argument to itself.
--
-- >>> let f = toFunction ("x" ** 2 + 1) (\case "x" -> id) :: Double -> Double
-- >>> f 3  -- 3 ** 2 + 1
-- 10.0
-- >>> f 10  -- 10 ** 2 + 1
-- 101.0
--
-- For another example, "x" could map the first element from a tuple argument,
-- and "y" could map the second element from the tuple argument.  I.e.,
-- for a tuple argument to the function, the first element will be used as "x"
-- and the second element will be used as "y".
--
-- >>> let m = \case "x" -> (\(x,_) -> x); "y" -> (\(_,y) -> y)
-- >>> let g = toFunction ("x" + 2 * "y") m :: (Double, Double) -> Double
-- >>> g (3,4)  -- 3 + 2 * 4
-- 11.0
-- >>> g (7,1)  -- 7 + 2 * 1
-- 9.0
toFunction ::
  (Floating b) =>
  -- | The expression to be converted into a function.
  Expression ->
  -- | Maps how the argument to the function should be mapped to a value for a symbol.
  -- E.g., "x" could map the first element in a tuple as the value to use in its place.
  (Text -> (a -> b)) ->
  -- | The function generated from the expression.
  (a -> b)
toFunction :: forall b a. Floating b => Expression -> (Text -> a -> b) -> a -> b
toFunction (Number Integer
n) Text -> a -> b
_ = b -> a -> b
forall a b. a -> b -> a
const (b -> a -> b) -> b -> a -> b
forall a b. (a -> b) -> a -> b
$ Integer -> b
forall a. Num a => Integer -> a
fromInteger Integer
n
toFunction (Symbol Text
s) Text -> a -> b
m = Text -> a -> b
m Text
s
toFunction (UnaryApply UnaryFunction
func Expression
x) Text -> a -> b
m = b -> b
f (b -> b) -> (a -> b) -> a -> b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> b
g
  where
    f :: b -> b
f = UnaryFunction -> b -> b
forall a. Floating a => UnaryFunction -> a -> a
getUnaryFunction UnaryFunction
func
    g :: a -> b
g = Expression -> (Text -> a -> b) -> a -> b
forall b a. Floating b => Expression -> (Text -> a -> b) -> a -> b
toFunction Expression
x Text -> a -> b
m
toFunction (BinaryApply BinaryFunction
func Expression
x Expression
y) Text -> a -> b
m = \a
v -> b -> b -> b
f (a -> b
g a
v) (a -> b
h a
v)
  where
    f :: b -> b -> b
f = BinaryFunction -> b -> b -> b
forall a. Floating a => BinaryFunction -> a -> a -> a
getBinaryFunction BinaryFunction
func
    g :: a -> b
g = Expression -> (Text -> a -> b) -> a -> b
forall b a. Floating b => Expression -> (Text -> a -> b) -> a -> b
toFunction Expression
x Text -> a -> b
m
    h :: a -> b
h = Expression -> (Text -> a -> b) -> a -> b
forall b a. Floating b => Expression -> (Text -> a -> b) -> a -> b
toFunction Expression
y Text -> a -> b
m