{-# LANGUAGE GADTs #-}
module Drasil.Code.CodeExpr.Lang where

import Prelude hiding (sqrt)
import Control.Lens ((^.))

import Drasil.Database (UID, HasUID(..))

import Language.Drasil.Expr.Lang
  (Completeness(..), ArithBinOp(..), EqBinOp(..),
   LABinOp(..), OrdBinOp(..), EqBinOp(..),
   VVVBinOp(..), VVNBinOp(..), NVVBinOp(..), ESSBinOp(..), ESBBinOp(..),
   AssocArithOper(..), AssocBoolOper(..), AssocConcatOper(..),
   UFunc(..), UFuncB(..), UFuncVV(..), UFuncVN(..))
import Language.Drasil.Expr.Class (ExprC(..), square)
import Language.Drasil.Literal.Class (LiteralC(..))
import Language.Drasil.Literal.Lang (Literal(..))
import Language.Drasil.Space (Space, RealInterval, DiscreteDomainDesc,
  DomainDesc(BoundedDD), RTopology(..))

-- * CodeExpr

-- | Expression language where all terms also denote a term in GOOL
--   (i.e. translation is total and meaning preserving).
data CodeExpr where
  -- | Brings literals into the expression language.
  Lit      :: Literal -> CodeExpr

  -- | Takes an associative arithmetic operator with a list of expressions.
  AssocA   :: AssocArithOper -> [CodeExpr] -> CodeExpr
  -- | Takes an associative boolean operator with a list of expressions.
  AssocB   :: AssocBoolOper  -> [CodeExpr] -> CodeExpr

  AssocC :: AssocConcatOper -> [CodeExpr] -> CodeExpr
  -- | C stands for "Chunk", for referring to a chunk in an expression.
  --   Implicitly assumes that the chunk has a symbol.
  C        :: UID -> CodeExpr
  -- | A function call accepts a list of parameters and a list of named parameters.
  --   For example
  --
  --   * F(x) is (FCall F [x] []).
  --   * F(x,y) would be (FCall F [x,y]).
  --   * F(x,n=y) would be (FCall F [x] [(n,y)]).
  FCall    :: UID -> [CodeExpr] -> [(UID, CodeExpr)] -> CodeExpr
  -- | Actor creation given 'UID', parameters, and named parameters.
  New      :: UID -> [CodeExpr] -> [(UID, CodeExpr)] -> CodeExpr
  -- | Message an actor:
  --
  --   * 1st 'UID' is the actor,
  --   * 2nd 'UID' is the method.
  Message  :: UID -> UID -> [CodeExpr] -> [(UID, CodeExpr)] -> CodeExpr
  -- | Access a field of an actor:
  --
  --   * 1st 'UID' is the actor,
  --   * 2nd 'UID' is the field.
  Field    :: UID -> UID -> CodeExpr
  -- | For multi-case expressions, each pair represents one case.
  Case     :: Completeness -> [(CodeExpr, CodeExpr)] -> CodeExpr
  -- | Represents a matrix of expressions.
  Matrix   :: [[CodeExpr]] -> CodeExpr
  -- | Represents a set of expressions
  Set      :: Space -> [CodeExpr] -> CodeExpr
  -- | used to refernce the (name + type = variable )
  Variable :: String -> CodeExpr -> CodeExpr
  -- | Unary operation for most functions (eg. sin, cos, log, etc.).
  UnaryOp       :: UFunc -> CodeExpr -> CodeExpr
  -- | Unary operation for @Bool -> Bool@ operations.
  UnaryOpB      :: UFuncB -> CodeExpr -> CodeExpr
  -- | Unary operation for @Vector -> Vector@ operations.
  UnaryOpVV     :: UFuncVV -> CodeExpr -> CodeExpr
  -- | Unary operation for @Vector -> Number@ operations.
  UnaryOpVN     :: UFuncVN -> CodeExpr -> CodeExpr

  -- | Binary operator for arithmetic between expressions (fractional, power, and subtraction).
  ArithBinaryOp :: ArithBinOp -> CodeExpr -> CodeExpr -> CodeExpr
  -- | Binary operator for equality between expressions.
  EqBinaryOp    :: EqBinOp -> CodeExpr -> CodeExpr -> CodeExpr
  -- | Binary operator for indexing two expressions.
  LABinaryOp    :: LABinOp -> CodeExpr -> CodeExpr -> CodeExpr
  -- | Binary operator for ordering expressions (less than, greater than, etc.).
  OrdBinaryOp   :: OrdBinOp -> CodeExpr -> CodeExpr -> CodeExpr
  -- | Binary operator for @Vector x Vector -> Vector@ operations (cross product).
  VVVBinaryOp   :: VVVBinOp -> CodeExpr -> CodeExpr -> CodeExpr
  -- | Binary operator for @Vector x Vector -> Number@ operations (dot product).
  VVNBinaryOp   :: VVNBinOp -> CodeExpr -> CodeExpr -> CodeExpr
  -- | Binary operator for @Number x Vector -> Vector@ operations (scaling).
  NVVBinaryOp   :: NVVBinOp -> CodeExpr -> CodeExpr -> CodeExpr
  -- | Set operator for Set + Set -> Set
  ESSBinaryOp :: ESSBinOp -> CodeExpr -> CodeExpr -> CodeExpr
  -- | Set operator for Element + Set -> Bool
  ESBBinaryOp :: ESBBinOp -> CodeExpr -> CodeExpr -> CodeExpr

  -- | Operators are generalized arithmetic operators over a 'DomainDesc'
  --   of an 'Expr'.  Could be called BigOp.
  --   ex: Summation is represented via 'Add' over a discrete domain.
  Operator :: AssocArithOper -> DiscreteDomainDesc CodeExpr CodeExpr -> CodeExpr -> CodeExpr
  -- | The expression is an element of a space.
  -- IsIn     :: Expr -> Space -> Expr
  -- | A different kind of 'IsIn'. A 'UID' is an element of an interval.
  RealI    :: UID -> RealInterval CodeExpr CodeExpr -> CodeExpr

instance LiteralC CodeExpr where
  str :: String -> CodeExpr
str      = Literal -> CodeExpr
Lit (Literal -> CodeExpr) -> (String -> Literal) -> String -> CodeExpr
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Literal
forall r. LiteralC r => String -> r
str
  int :: Integer -> CodeExpr
int      = Literal -> CodeExpr
Lit (Literal -> CodeExpr)
-> (Integer -> Literal) -> Integer -> CodeExpr
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Integer -> Literal
forall r. LiteralC r => Integer -> r
int
  dbl :: Double -> CodeExpr
dbl      = Literal -> CodeExpr
Lit (Literal -> CodeExpr) -> (Double -> Literal) -> Double -> CodeExpr
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Double -> Literal
forall r. LiteralC r => Double -> r
dbl
  exactDbl :: Integer -> CodeExpr
exactDbl = Literal -> CodeExpr
Lit (Literal -> CodeExpr)
-> (Integer -> Literal) -> Integer -> CodeExpr
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Integer -> Literal
forall r. LiteralC r => Integer -> r
exactDbl
  perc :: Integer -> Integer -> CodeExpr
perc Integer
l Integer
r = Literal -> CodeExpr
Lit (Literal -> CodeExpr) -> Literal -> CodeExpr
forall a b. (a -> b) -> a -> b
$ Integer -> Integer -> Literal
forall r. LiteralC r => Integer -> Integer -> r
perc Integer
l Integer
r

instance ExprC CodeExpr where
  lit :: Literal -> CodeExpr
lit = Literal -> CodeExpr
Lit

  -- | Smart constructor for equating two expressions.
  $= :: CodeExpr -> CodeExpr -> CodeExpr
($=) = EqBinOp -> CodeExpr -> CodeExpr -> CodeExpr
EqBinaryOp EqBinOp
Eq
  -- | Smart constructor for showing that two expressions are not equal.
  $!= :: CodeExpr -> CodeExpr -> CodeExpr
($!=) = EqBinOp -> CodeExpr -> CodeExpr -> CodeExpr
EqBinaryOp EqBinOp
NEq

  -- | Smart constructor for ordering two equations.
  -- | Less than.
  $< :: CodeExpr -> CodeExpr -> CodeExpr
($<) = OrdBinOp -> CodeExpr -> CodeExpr -> CodeExpr
OrdBinaryOp OrdBinOp
Lt
  -- | Greater than.
  $> :: CodeExpr -> CodeExpr -> CodeExpr
($>) = OrdBinOp -> CodeExpr -> CodeExpr -> CodeExpr
OrdBinaryOp OrdBinOp
Gt
  -- | Less than or equal to.
  $<= :: CodeExpr -> CodeExpr -> CodeExpr
($<=) = OrdBinOp -> CodeExpr -> CodeExpr -> CodeExpr
OrdBinaryOp OrdBinOp
LEq
  -- | Greater than or equal to.
  $>= :: CodeExpr -> CodeExpr -> CodeExpr
($>=) = OrdBinOp -> CodeExpr -> CodeExpr -> CodeExpr
OrdBinaryOp OrdBinOp
GEq

  -- | Smart constructor for the dot product of two equations.
  $. :: CodeExpr -> CodeExpr -> CodeExpr
($.) = VVNBinOp -> CodeExpr -> CodeExpr -> CodeExpr
VVNBinaryOp VVNBinOp
Dot

  -- | Add two expressions.
  $+ :: CodeExpr -> CodeExpr -> CodeExpr
($+) (Lit (Int Integer
0)) CodeExpr
r = CodeExpr
r
  ($+) CodeExpr
l (Lit (Int Integer
0)) = CodeExpr
l
  ($+) (Lit (Dbl Double
0)) CodeExpr
r = CodeExpr
r
  ($+) CodeExpr
l (Lit (Dbl Double
0)) = CodeExpr
l
  ($+) CodeExpr
l (Lit (ExactDbl Integer
0)) = CodeExpr
l
  ($+) (Lit (ExactDbl Integer
0)) CodeExpr
r = CodeExpr
r
  ($+) (AssocA AssocArithOper
Add [CodeExpr]
l) (AssocA AssocArithOper
Add [CodeExpr]
r) = AssocArithOper -> [CodeExpr] -> CodeExpr
AssocA AssocArithOper
Add ([CodeExpr]
l [CodeExpr] -> [CodeExpr] -> [CodeExpr]
forall a. [a] -> [a] -> [a]
++ [CodeExpr]
r)
  ($+) (AssocA AssocArithOper
Add [CodeExpr]
l) CodeExpr
r = AssocArithOper -> [CodeExpr] -> CodeExpr
AssocA AssocArithOper
Add ([CodeExpr]
l [CodeExpr] -> [CodeExpr] -> [CodeExpr]
forall a. [a] -> [a] -> [a]
++ [CodeExpr
r])
  ($+) CodeExpr
l (AssocA AssocArithOper
Add [CodeExpr]
r) = AssocArithOper -> [CodeExpr] -> CodeExpr
AssocA AssocArithOper
Add (CodeExpr
l CodeExpr -> [CodeExpr] -> [CodeExpr]
forall a. a -> [a] -> [a]
: [CodeExpr]
r)
  ($+) CodeExpr
l CodeExpr
r = AssocArithOper -> [CodeExpr] -> CodeExpr
AssocA AssocArithOper
Add [CodeExpr
l, CodeExpr
r]

  -- | Multiply two expressions.
  $* :: CodeExpr -> CodeExpr -> CodeExpr
($*) (Lit (Int Integer
1)) CodeExpr
r = CodeExpr
r
  ($*) CodeExpr
l (Lit (Int Integer
1)) = CodeExpr
l
  ($*) (Lit (Dbl Double
1.0)) CodeExpr
r = CodeExpr
r
  ($*) CodeExpr
l (Lit (Dbl Double
1.0)) = CodeExpr
l
  ($*) CodeExpr
l (Lit (ExactDbl Integer
1)) = CodeExpr
l
  ($*) (Lit (ExactDbl Integer
1)) CodeExpr
r = CodeExpr
r
  ($*) (AssocA AssocArithOper
Mul [CodeExpr]
l) (AssocA AssocArithOper
Mul [CodeExpr]
r) = AssocArithOper -> [CodeExpr] -> CodeExpr
AssocA AssocArithOper
Mul ([CodeExpr]
l [CodeExpr] -> [CodeExpr] -> [CodeExpr]
forall a. [a] -> [a] -> [a]
++ [CodeExpr]
r)
  ($*) (AssocA AssocArithOper
Mul [CodeExpr]
l) CodeExpr
r = AssocArithOper -> [CodeExpr] -> CodeExpr
AssocA AssocArithOper
Mul ([CodeExpr]
l [CodeExpr] -> [CodeExpr] -> [CodeExpr]
forall a. [a] -> [a] -> [a]
++ [CodeExpr
r])
  ($*) CodeExpr
l (AssocA AssocArithOper
Mul [CodeExpr]
r) = AssocArithOper -> [CodeExpr] -> CodeExpr
AssocA AssocArithOper
Mul (CodeExpr
l CodeExpr -> [CodeExpr] -> [CodeExpr]
forall a. a -> [a] -> [a]
: [CodeExpr]
r)
  ($*) CodeExpr
l CodeExpr
r = AssocArithOper -> [CodeExpr] -> CodeExpr
AssocA AssocArithOper
Mul [CodeExpr
l,CodeExpr
r]

  -- | Smart constructor for subtracting two expressions.
  $- :: CodeExpr -> CodeExpr -> CodeExpr
($-) = ArithBinOp -> CodeExpr -> CodeExpr -> CodeExpr
ArithBinaryOp ArithBinOp
Subt
  -- | Smart constructor for dividing two expressions.
  $/ :: CodeExpr -> CodeExpr -> CodeExpr
($/) = ArithBinOp -> CodeExpr -> CodeExpr -> CodeExpr
ArithBinaryOp ArithBinOp
Frac
  -- | Smart constructor for rasing the first expression to the power of the second.
  $^ :: CodeExpr -> CodeExpr -> CodeExpr
($^) = ArithBinOp -> CodeExpr -> CodeExpr -> CodeExpr
ArithBinaryOp ArithBinOp
Pow

  -- | Smart constructor for the boolean /and/ operator.
  CodeExpr
a $&& :: CodeExpr -> CodeExpr -> CodeExpr
$&& CodeExpr
b = AssocBoolOper -> [CodeExpr] -> CodeExpr
AssocB AssocBoolOper
And [CodeExpr
a, CodeExpr
b]
  -- | Smart constructor for the boolean /or/ operator.
  CodeExpr
a $|| :: CodeExpr -> CodeExpr -> CodeExpr
$|| CodeExpr
b = AssocBoolOper -> [CodeExpr] -> CodeExpr
AssocB AssocBoolOper
Or  [CodeExpr
a, CodeExpr
b]

  in' :: CodeExpr -> CodeExpr -> CodeExpr
in' = ESBBinOp -> CodeExpr -> CodeExpr -> CodeExpr
ESBBinaryOp ESBBinOp
SContains

  -- | Smart constructor for taking the absolute value of an expression.
  abs_ :: CodeExpr -> CodeExpr
abs_ = UFunc -> CodeExpr -> CodeExpr
UnaryOp UFunc
Abs

  -- | Smart constructor for negating an expression.
  neg :: CodeExpr -> CodeExpr
neg = UFunc -> CodeExpr -> CodeExpr
UnaryOp UFunc
Neg

  -- | Smart constructor to take the log of an expression.
  log :: CodeExpr -> CodeExpr
log = UFunc -> CodeExpr -> CodeExpr
UnaryOp UFunc
Log

  -- | Smart constructor to take the ln of an expression.
  ln :: CodeExpr -> CodeExpr
ln = UFunc -> CodeExpr -> CodeExpr
UnaryOp UFunc
Ln

  -- | Smart constructor to take the square root of an expression.
  sqrt :: CodeExpr -> CodeExpr
sqrt = UFunc -> CodeExpr -> CodeExpr
UnaryOp UFunc
Sqrt

  -- | Smart constructor to apply sin to an expression.
  sin :: CodeExpr -> CodeExpr
sin = UFunc -> CodeExpr -> CodeExpr
UnaryOp UFunc
Sin

  -- | Smart constructor to apply cos to an expression.
  cos :: CodeExpr -> CodeExpr
cos = UFunc -> CodeExpr -> CodeExpr
UnaryOp UFunc
Cos

  -- | Smart constructor to apply tan to an expression.
  tan :: CodeExpr -> CodeExpr
tan = UFunc -> CodeExpr -> CodeExpr
UnaryOp UFunc
Tan

  -- | Smart constructor to apply sec to an expression.
  sec :: CodeExpr -> CodeExpr
sec = UFunc -> CodeExpr -> CodeExpr
UnaryOp UFunc
Sec

  -- | Smart constructor to apply csc to an expression.
  csc :: CodeExpr -> CodeExpr
csc = UFunc -> CodeExpr -> CodeExpr
UnaryOp UFunc
Csc

  -- | Smart constructor to apply cot to an expression.
  cot :: CodeExpr -> CodeExpr
cot = UFunc -> CodeExpr -> CodeExpr
UnaryOp UFunc
Cot

  -- | Smart constructor to apply arcsin to an expression.
  arcsin :: CodeExpr -> CodeExpr
arcsin = UFunc -> CodeExpr -> CodeExpr
UnaryOp UFunc
Arcsin

  -- | Smart constructor to apply arccos to an expression.
  arccos :: CodeExpr -> CodeExpr
arccos = UFunc -> CodeExpr -> CodeExpr
UnaryOp UFunc
Arccos

  -- | Smart constructor to apply arctan to an expression.
  arctan :: CodeExpr -> CodeExpr
arctan = UFunc -> CodeExpr -> CodeExpr
UnaryOp UFunc
Arctan

  -- | Smart constructor for the exponential (base e) function.
  exp :: CodeExpr -> CodeExpr
exp = UFunc -> CodeExpr -> CodeExpr
UnaryOp UFunc
Exp

  -- | Smart constructor for calculating the dimension of a vector.
  dim :: CodeExpr -> CodeExpr
dim = UFuncVN -> CodeExpr -> CodeExpr
UnaryOpVN UFuncVN
Dim

  -- | Smart constructor for calculating the normal form of a vector.
  norm :: CodeExpr -> CodeExpr
norm = UFuncVN -> CodeExpr -> CodeExpr
UnaryOpVN UFuncVN
Norm

  -- | Smart constructor for negating vectors.
  negVec :: CodeExpr -> CodeExpr
negVec = UFuncVV -> CodeExpr -> CodeExpr
UnaryOpVV UFuncVV
NegV
  -- | And more general scaling
  vScale :: CodeExpr -> CodeExpr -> CodeExpr
vScale = NVVBinOp -> CodeExpr -> CodeExpr -> CodeExpr
NVVBinaryOp NVVBinOp
Scale

  -- | Smart constructor for applying logical negation to an expression.
  not_ :: CodeExpr -> CodeExpr
not_ = UFuncB -> CodeExpr -> CodeExpr
UnaryOpB UFuncB
Not

  -- | Smart constructor for indexing.
  idx :: CodeExpr -> CodeExpr -> CodeExpr
idx = LABinOp -> CodeExpr -> CodeExpr -> CodeExpr
LABinaryOp LABinOp
Index

  idxOf :: CodeExpr -> CodeExpr -> CodeExpr
idxOf = LABinOp -> CodeExpr -> CodeExpr -> CodeExpr
LABinaryOp LABinOp
IndexOf
  -- | Integrate over some expression with bounds (∫).
  defint :: Symbol -> CodeExpr -> CodeExpr -> CodeExpr -> CodeExpr
defint Symbol
v CodeExpr
low CodeExpr
high = AssocArithOper
-> DiscreteDomainDesc CodeExpr CodeExpr -> CodeExpr -> CodeExpr
Operator AssocArithOper
Add (Symbol
-> RTopology
-> CodeExpr
-> CodeExpr
-> DiscreteDomainDesc CodeExpr CodeExpr
forall a b.
Symbol -> RTopology -> a -> b -> DomainDesc 'Discrete a b
BoundedDD Symbol
v RTopology
Continuous CodeExpr
low CodeExpr
high)

  -- | Sum over some expression with bounds (∑).
  defsum :: Symbol -> CodeExpr -> CodeExpr -> CodeExpr -> CodeExpr
defsum Symbol
v CodeExpr
low CodeExpr
high = AssocArithOper
-> DiscreteDomainDesc CodeExpr CodeExpr -> CodeExpr -> CodeExpr
Operator AssocArithOper
Add (Symbol
-> RTopology
-> CodeExpr
-> CodeExpr
-> DiscreteDomainDesc CodeExpr CodeExpr
forall a b.
Symbol -> RTopology -> a -> b -> DomainDesc 'Discrete a b
BoundedDD Symbol
v RTopology
Discrete CodeExpr
low CodeExpr
high)

  -- | Product over some expression with bounds (∏).
  defprod :: Symbol -> CodeExpr -> CodeExpr -> CodeExpr -> CodeExpr
defprod Symbol
v CodeExpr
low CodeExpr
high = AssocArithOper
-> DiscreteDomainDesc CodeExpr CodeExpr -> CodeExpr -> CodeExpr
Operator AssocArithOper
Mul (Symbol
-> RTopology
-> CodeExpr
-> CodeExpr
-> DiscreteDomainDesc CodeExpr CodeExpr
forall a b.
Symbol -> RTopology -> a -> b -> DomainDesc 'Discrete a b
BoundedDD Symbol
v RTopology
Discrete CodeExpr
low CodeExpr
high)

  -- | Smart constructor for 'real interval' membership.
  realInterval :: forall c.
HasUID c =>
c -> RealInterval CodeExpr CodeExpr -> CodeExpr
realInterval c
c = UID -> RealInterval CodeExpr CodeExpr -> CodeExpr
RealI (c
c c -> Getting UID c UID -> UID
forall s a. s -> Getting a s a -> a
^. Getting UID c UID
forall c. HasUID c => Getter c UID
Getter c UID
uid)

  -- | Euclidean function : takes a vector and returns the sqrt of the sum-of-squares.
  euclidean :: [CodeExpr] -> CodeExpr
euclidean = CodeExpr -> CodeExpr
forall r. ExprC r => r -> r
sqrt (CodeExpr -> CodeExpr)
-> ([CodeExpr] -> CodeExpr) -> [CodeExpr] -> CodeExpr
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (CodeExpr -> CodeExpr -> CodeExpr) -> [CodeExpr] -> CodeExpr
forall a. (a -> a -> a) -> [a] -> a
forall (t :: * -> *) a. Foldable t => (a -> a -> a) -> t a -> a
foldr1 CodeExpr -> CodeExpr -> CodeExpr
forall r. ExprC r => r -> r -> r
($+) ([CodeExpr] -> CodeExpr)
-> ([CodeExpr] -> [CodeExpr]) -> [CodeExpr] -> CodeExpr
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (CodeExpr -> CodeExpr) -> [CodeExpr] -> [CodeExpr]
forall a b. (a -> b) -> [a] -> [b]
map CodeExpr -> CodeExpr
forall r. (ExprC r, LiteralC r) => r -> r
square

  -- | Smart constructor to cross product two expressions.
  cross :: CodeExpr -> CodeExpr -> CodeExpr
cross = VVVBinOp -> CodeExpr -> CodeExpr -> CodeExpr
VVVBinaryOp VVVBinOp
Cross

  -- | Adding vectors
  vAdd :: CodeExpr -> CodeExpr -> CodeExpr
vAdd = VVVBinOp -> CodeExpr -> CodeExpr -> CodeExpr
VVVBinaryOp VVVBinOp
VAdd
  -- | Subtracting vectors
  vSub :: CodeExpr -> CodeExpr -> CodeExpr
vSub = VVVBinOp -> CodeExpr -> CodeExpr -> CodeExpr
VVVBinaryOp VVVBinOp
VSub

  -- | Smart constructor for case statements with a complete set of cases.
  completeCase :: [(CodeExpr, CodeExpr)] -> CodeExpr
completeCase = Completeness -> [(CodeExpr, CodeExpr)] -> CodeExpr
Case Completeness
Complete

  -- | Smart constructor for case statements with an incomplete set of cases.
  incompleteCase :: [(CodeExpr, CodeExpr)] -> CodeExpr
incompleteCase = Completeness -> [(CodeExpr, CodeExpr)] -> CodeExpr
Case Completeness
Incomplete

  matrix :: [[CodeExpr]] -> CodeExpr
matrix = [[CodeExpr]] -> CodeExpr
Matrix

  set' :: Space -> [CodeExpr] -> CodeExpr
set' = Space -> [CodeExpr] -> CodeExpr
Set
  -- | Applies a given function with a list of parameters.
  apply :: forall f. (HasUID f, HasSymbol f) => f -> [CodeExpr] -> CodeExpr
apply f
f [] = f -> CodeExpr
forall c. (HasUID c, HasSymbol c) => c -> CodeExpr
forall r c. (ExprC r, HasUID c, HasSymbol c) => c -> r
sy f
f
  apply f
f [CodeExpr]
ps = UID -> [CodeExpr] -> [(UID, CodeExpr)] -> CodeExpr
FCall (f
f f -> Getting UID f UID -> UID
forall s a. s -> Getting a s a -> a
^. Getting UID f UID
forall c. HasUID c => Getter c UID
Getter f UID
uid) [CodeExpr]
ps []

  -- Note how |sy| 'enforces' having a symbol
  -- | Create an 'Expr' from a 'Symbol'ic Chunk.
  sy :: forall c. (HasUID c, HasSymbol c) => c -> CodeExpr
sy c
x = UID -> CodeExpr
C (c
x c -> Getting UID c UID -> UID
forall s a. s -> Getting a s a -> a
^. Getting UID c UID
forall c. HasUID c => Getter c UID
Getter c UID
uid)