scalus.uplc.transform

Members list

Type members

Classlikes

Replace nested Apply with Case/Constr

Replace nested Apply with Case/Constr

For example, replace (apply (apply (apply f a) b) c) with (case (constr 0 [a, b, c]) f). This is more memory/cpu efficient than nested Apply at least in Plutus V3 Plomin HF, protocol version 10.

With current machine costs, Apply costs 100 memory and 16000 cpu, same for Case/Constr. Hence (case (constr 0 [a, b, c]) f) costs 200 memory and 32000 cpu, while (apply (apply (apply f a) b) c) costs 300 memory and 48000 cpu.

Attributes

Supertypes
class Object
trait Matchable
class Any
Self type
object EtaReduce

Performs eta-reduction on a term.

Performs eta-reduction on a term.

Attributes

See also
Supertypes
class Object
trait Matchable
class Any
Self type
EtaReduce.type

Extract forced builtins to top level

Extract forced builtins to top level

For example, replace (force (force (builtin fstPair))) with (lam builtin_FstPair (builtin_FstPair (pair true false)) (! (! __builtin_FstPair))). This is more memory/cpu efficient than nested Force at least in Plutus V3 Plomin HF, protocol version 10.

With current machine costs, Force costs 100 memory and 16000 cpu, same for Builtin. Hence (lam builtin_FstPair (builtin_FstPair (pair true false)) (! (! __builtin_FstPair))) costs 200 memory and 32000 cpu, while (force (force (builtin fstPair))) costs 300 memory and 48000 cpu.

Attributes

Supertypes
class Object
trait Matchable
class Any
Self type
object Inliner

Attributes

Supertypes
class Object
trait Matchable
class Any
Self type
Inliner.type
object StrictIf

Optimizes if-then-else expressions by converting lazy branches to strict evaluation when safe.

Optimizes if-then-else expressions by converting lazy branches to strict evaluation when safe.

==Background==

UPLC (Untyped Plutus Core) uses strict evaluation: all function arguments are evaluated before the function is applied. However, for conditional expressions using IfThenElse, we need lazy evaluation to avoid evaluating both branches.

The standard compilation generates:

Force(Apply(Apply(Apply(Force(Builtin(IfThenElse)), condition), Delay(thenBranch)), Delay(elseBranch)))

This pattern has a cost:

  • 2 Delay nodes to suspend branch evaluation
  • 1 Force node to evaluate the selected branch
  • Total: '''3 extra term node evaluations per if-then-else'''

==The Optimization==

When both branches are "simple values" that evaluate to exactly 1 term, we can safely evaluate them strictly, removing the Delay/Force overhead:

Apply(Apply(Apply(Force(Builtin(IfThenElse)), condition), thenBranch), elseBranch)

This saves 3 term node evaluations, improving performance without changing semantics.

==Simple Values (Single-Term Evaluation)==

A term is considered "simple" if it evaluates to exactly 1 term:

  • Var: Variable lookup (1 term)
  • Const: Constant value (1 term)
  • LamAbs: Lambda abstraction - not executed until applied (1 term)
  • Builtin: Builtin function reference - not executed until applied (1 term)
  • Delay: Suspended computation - not executed (1 term)
  • Constr(_, Nil): Empty constructor (1 term)

Terms that are NOT simple (multi-term evaluation):

  • Apply: Requires evaluating function + argument (3+ terms)
  • Force: Requires evaluating the forced term (2+ terms)
  • Case: Requires evaluating scrutinee + pattern matching (2+ terms)
  • Constr(_, args) with args: Requires evaluating each argument (1 + n terms)
  • Error: Will fail immediately

==Example==

// Original: if condition then 42 else 100
Force(Apply(Apply(Apply(Force(Builtin(IfThenElse)), condition), Delay(Const(42))), Delay(Const(100))))
// Cost: 5 term evaluations (Force + Apply + Apply + Apply + Force + 2 Delay + selected Const)

// Optimized: both branches are constants (simple values)
Apply(Apply(Apply(Force(Builtin(IfThenElse)), condition), Const(42)), Const(100))
// Cost: 2 term evaluations (Force + Apply + Apply + Apply + selected Const)
// Savings: 3 term evaluations (2 Delay + 1 Force)

Attributes

See also

scalus.uplc.transform.EtaReduce for another UPLC optimization

scalus.uplc.transform.Inliner for beta-reduction and dead code elimination

Supertypes
class Object
trait Matchable
class Any
Self type
StrictIf.type
object TermAnalysis

Static analysis utilities for UPLC terms.

Static analysis utilities for UPLC terms.

Provides analysis methods for determining properties of UPLC terms that are useful for optimization and transformation passes.

Attributes

Supertypes
class Object
trait Matchable
class Any
Self type