common : { add : Maybe CoreFn.Name.Name, sub : Maybe CoreFn.Name.Name, mul : Maybe CoreFn.Name.Name, div : Maybe CoreFn.Name.Name, neg : Maybe CoreFn.Name.Name } -> (ann -> ann -> ann) -> CoreFn.Expr.Expr ann -> CoreFn.Expr.Expr ann
A convenient helper to eliminate common maths expressions and other operators.
Like all the optimisations in this module this will only eliminate expressions
that only contain literals, but when combined with the constant propagation
helpers defined in ConstProp
you can eliminate
constant variables too.
This optimisation is applied bottom-up, so it will eliminate compound expressions
like 1 + 2 * 3
(assuming you provide names for your add
and mul
operators).
custom : List (CoreFn.Expr.Expr ann -> Maybe (CoreFn.Expr.Expr ann)) -> CoreFn.Expr.Expr ann -> CoreFn.Expr.Expr ann
Allows you to supply a list of custom eliminations that may or may not
succeed. Best used in combination with the helpers defined elsewhere in this
module like unop
, binop
, fn
, and so on.
unop : CoreFn.Name.Name -> (CoreFn.Expr.Lit (CoreFn.Expr.Expr ann) -> Maybe (CoreFn.Expr.Lit (CoreFn.Expr.Expr ann))) -> CoreFn.Expr.Expr ann -> Maybe (CoreFn.Expr.Expr ann)
Eliminate a unary operator applied to some literal. We could implement an elimination for simple negation like so:
import CoreFn.Expr as Expr exposing (Expr)
import CoreFn.Name as Name
import CoreFn.Optimise.ConstFold as ConstFold
negate : Expr -> Maybe Expr
negate =
ConstFold.unop
(Name.Lower "negate")
(\lit ->
case lit of
Expr.Int int ->
Just <| Expr.Int <| Basics.negate int
Expr.Num num ->
Just <| Expr.Num <| Basics.negate num
_ ->
Nothing
)
binop : CoreFn.Name.Name -> (ann -> ann -> ann) -> (CoreFn.Expr.Lit (CoreFn.Expr.Expr ann) -> CoreFn.Expr.Lit (CoreFn.Expr.Expr ann) -> Maybe (CoreFn.Expr.Lit (CoreFn.Expr.Expr ann))) -> CoreFn.Expr.Expr ann -> Maybe (CoreFn.Expr.Expr ann)
Just like unop
, we can eliminate a binary operator applied to two
literal values with this function. You can probably guess how to implement
something like addition (there are even helpers to make
that easier) so let's look at a different example.
We could eliminate object/record access like so:
import CoreFn.Expr as Expr exposing (Expr)
import CoreFn.Name as Name
import CoreFn.Optimise.ConstFold as ConstFold
access : Expr -> Maybe Expr
access =
ConstFold.binop
(Name.Lower "access")
(\lhs rhs ->
case ( lhs, rhs ) of
( Expr.Str key, Expr.Obj obj ) ->
List.filter (Tuple.first >> (==) key) obj
|> List.head
|> Maybe.map Tuple.second
_ ->
Nothing
)
Such that if we're given...
{ foo = 1 }.foo
...we can eliminate the whole thing to...
1
intUnop : CoreFn.Name.Name -> (Basics.Int -> Basics.Int) -> CoreFn.Expr.Expr ann -> Maybe (CoreFn.Expr.Expr ann)
numUnop : CoreFn.Name.Name -> (Basics.Float -> Basics.Float) -> CoreFn.Expr.Expr ann -> Maybe (CoreFn.Expr.Expr ann)
strUnop : CoreFn.Name.Name -> (String -> String) -> CoreFn.Expr.Expr ann -> Maybe (CoreFn.Expr.Expr ann)
intBinop : CoreFn.Name.Name -> (ann -> ann -> ann) -> (Basics.Int -> Basics.Int -> Basics.Int) -> CoreFn.Expr.Expr ann -> Maybe (CoreFn.Expr.Expr ann)
numBinop : CoreFn.Name.Name -> (ann -> ann -> ann) -> (Basics.Float -> Basics.Float -> Basics.Float) -> CoreFn.Expr.Expr ann -> Maybe (CoreFn.Expr.Expr ann)
strBinop : CoreFn.Name.Name -> (ann -> ann -> ann) -> (String -> String -> String) -> CoreFn.Expr.Expr ann -> Maybe (CoreFn.Expr.Expr ann)
The following collection of functions reduce some of the boilerplate when
optimising for n-arity functions. Because the CoreFn
expression models
function application as repeaded application of single-argument functions, there
ends up being quite a bit of nesting if you want to pull out 3, 4, ..8 arguments!
f : CoreFn.Name.Name -> (CoreFn.Expr.Expr ann -> Maybe (CoreFn.Expr.Expr ann)) -> CoreFn.Expr.Expr ann -> Maybe (CoreFn.Expr.Expr ann)
f2 : CoreFn.Name.Name -> (CoreFn.Expr.Expr ann -> CoreFn.Expr.Expr ann -> Maybe (CoreFn.Expr.Expr ann)) -> CoreFn.Expr.Expr ann -> Maybe (CoreFn.Expr.Expr ann)
f3 : CoreFn.Name.Name -> (CoreFn.Expr.Expr ann -> CoreFn.Expr.Expr ann -> CoreFn.Expr.Expr ann -> Maybe (CoreFn.Expr.Expr ann)) -> CoreFn.Expr.Expr ann -> Maybe (CoreFn.Expr.Expr ann)
f4 : CoreFn.Name.Name -> (CoreFn.Expr.Expr ann -> CoreFn.Expr.Expr ann -> CoreFn.Expr.Expr ann -> CoreFn.Expr.Expr ann -> Maybe (CoreFn.Expr.Expr ann)) -> CoreFn.Expr.Expr ann -> Maybe (CoreFn.Expr.Expr ann)
f5 : CoreFn.Name.Name -> (CoreFn.Expr.Expr ann -> CoreFn.Expr.Expr ann -> CoreFn.Expr.Expr ann -> CoreFn.Expr.Expr ann -> CoreFn.Expr.Expr ann -> Maybe (CoreFn.Expr.Expr ann)) -> CoreFn.Expr.Expr ann -> Maybe (CoreFn.Expr.Expr ann)
f6 : CoreFn.Name.Name -> (CoreFn.Expr.Expr ann -> CoreFn.Expr.Expr ann -> CoreFn.Expr.Expr ann -> CoreFn.Expr.Expr ann -> CoreFn.Expr.Expr ann -> CoreFn.Expr.Expr ann -> Maybe (CoreFn.Expr.Expr ann)) -> CoreFn.Expr.Expr ann -> Maybe (CoreFn.Expr.Expr ann)
f7 : CoreFn.Name.Name -> (CoreFn.Expr.Expr ann -> CoreFn.Expr.Expr ann -> CoreFn.Expr.Expr ann -> CoreFn.Expr.Expr ann -> CoreFn.Expr.Expr ann -> CoreFn.Expr.Expr ann -> CoreFn.Expr.Expr ann -> Maybe (CoreFn.Expr.Expr ann)) -> CoreFn.Expr.Expr ann -> Maybe (CoreFn.Expr.Expr ann)
f8 : CoreFn.Name.Name -> (CoreFn.Expr.Expr ann -> CoreFn.Expr.Expr ann -> CoreFn.Expr.Expr ann -> CoreFn.Expr.Expr ann -> CoreFn.Expr.Expr ann -> CoreFn.Expr.Expr ann -> CoreFn.Expr.Expr ann -> CoreFn.Expr.Expr ann -> Maybe (CoreFn.Expr.Expr ann)) -> CoreFn.Expr.Expr ann -> Maybe (CoreFn.Expr.Expr ann)