From 94dd23773f57f3da82329a912d71c3ad8973c1a5 Mon Sep 17 00:00:00 2001 From: Jacco <4022046+basetunnel@users.noreply.github.com> Date: Fri, 14 Nov 2025 15:52:46 +0100 Subject: [PATCH 1/6] WIP casing constants docs --- .../docs/delve-deeper/casing-constants.md | 119 ++++++++++++++++++ 1 file changed, 119 insertions(+) create mode 100644 doc/docusaurus/docs/delve-deeper/casing-constants.md diff --git a/doc/docusaurus/docs/delve-deeper/casing-constants.md b/doc/docusaurus/docs/delve-deeper/casing-constants.md new file mode 100644 index 00000000000..984626c682d --- /dev/null +++ b/doc/docusaurus/docs/delve-deeper/casing-constants.md @@ -0,0 +1,119 @@ +--- +sidebar_position: 26 +--- + +# Casing on built-in types in UPLC + +Starting with _intra-era hard fork_, UPLC supports a new way of processing +values of built-in types, such as `Integer` and `Data`. The `Case` construct, +which was originally introduced for [sums-of-products](), can now also be used +to case-split on such values. + +Using `Case` in UPLC programs can make processing of built-in types more +efficient, for example when dealing with `ScriptContext`, which is encoded using +`Data`. + +Depending on the built-in type, a certain order of branches is expected, and not +necessarily all values can be matched using `Case`. + +## Bool + +For booleans, there are two ways how `Case` may be used. Either with two +branches, where the first is the false branch, and the second the true branch. + +``` +case b + + +``` + + +□ does case evaluate its branches? + + + + +, Pair, Uni + + + +## Integer + +## List + +## Data + + + +# How to use built-in casing in Plinth + +Compiler flag, functions. + + +# Pattern matching and Case + +When you use pattern matching in Plinth, such as in a `case` expression, the +generated UPLC code will depend on the type of the value being matched on. + +□ Is this true or only on the UPLC level, i.e. does the compiler compile into +case or something else for built-in datatypes. For example, casing on integers +is limited to non-negative branches, and BuiltinData only to Data.Constr + +Usage in Plinth (if builtincasing flag): +(searching for BuiltinCasing) +- Bool matcher + +"built-in terms" (not built-in functions apparently, for those see below) + +- casePair (defineBuiltinTerm) +- caseList (defineBuiltinTerm) + +Built-in functions that are mapped to case instead of their built-in: +- ifThenElse +- fstPair +- sndPair +- chooseUnit + +## Case on built-in datatypes + +As of ..., pattern matching of most built-in types + +### Booleans + +### Integers + +### BuiltinData + +Only works on Data.Constr constructors + +□ TODO: how will case be handled + + +## Algebraic datatypes + +Datatypes defined using `data` can be compiled with different encodings (see +[Encoding Data Types in UPLC](./encoding)). Consequently, a `case` expression in +Plinth will generate different UPLC. + +### SOP Encoding (Sums-of-products) + +This is the default for ADTs. The resulting UPLC will uses UPLC's `case` syntax, see the [SOP example](./encoding#sums-of-products). + +### Scott Encoding + +When enabling this encoding, the resulting UPLC will use a polymorphic matching +function of the Scott encoding, see the [Scott Encoding +example](encoding#scott-encoding). + + + +# GHC's pattern match compiler + +Plinth supports for most pattern matching features of GHC, because it uses GHC's +desugaring pass. Complex patterns are generally transformed into nested `case` +expressions. The general algorithm for compiling pattern matching is described +in [The Implementation of Functional Programming Languages, Chapter +4](https://www.microsoft.com/en-us/research/wp-content/uploads/1987/01/slpj-book-1987-small.pdf). +More detail about language extensions regarding pattern matching can be found in +the [GHC User +Guide](https://ghc.gitlab.haskell.org/ghc/doc/users_guide/exts/patterns.html). From 332a1b95d579a3da686be372743731b80fcf5264 Mon Sep 17 00:00:00 2001 From: Jacco <4022046+basetunnel@users.noreply.github.com> Date: Mon, 17 Nov 2025 10:19:56 +0100 Subject: [PATCH 2/6] More WIP on casing constants in Plinth guide --- .../docs/delve-deeper/casing-constants.md | 54 +++++++++++++------ 1 file changed, 39 insertions(+), 15 deletions(-) diff --git a/doc/docusaurus/docs/delve-deeper/casing-constants.md b/doc/docusaurus/docs/delve-deeper/casing-constants.md index 984626c682d..65f165b51a8 100644 --- a/doc/docusaurus/docs/delve-deeper/casing-constants.md +++ b/doc/docusaurus/docs/delve-deeper/casing-constants.md @@ -5,42 +5,66 @@ sidebar_position: 26 # Casing on built-in types in UPLC Starting with _intra-era hard fork_, UPLC supports a new way of processing -values of built-in types, such as `Integer` and `Data`. The `Case` construct, -which was originally introduced for [sums-of-products](), can now also be used -to case-split on such values. +values of some built-in types, such as `Integer` and `Data`. The `case` +construct, which was originally introduced for [sums-of-products](), can also be +used to case-split on such values. -Using `Case` in UPLC programs can make processing of built-in types more +Using `case` in UPLC programs can make processing of built-in types more efficient, for example when dealing with `ScriptContext`, which is encoded using -`Data`. +`Data`. Even types like `Bool` -Depending on the built-in type, a certain order of branches is expected, and not -necessarily all values can be matched using `Case`. +Depending on the built-in type, a certain order and amount of branches is +expected, and not necessarily all values can be matched using `case`. ## Bool -For booleans, there are two ways how `Case` may be used. Either with two -branches, where the first is the false branch, and the second the true branch. +Booleans can be used in `case` with one or two branches, where the first is the +false branch. Boolean negation can be written as: ``` -case b - - +\b -> + case b + false + true ``` +When only one branch is provided, script execution will fail when the boolean +evaluates to `true`. -□ does case evaluate its branches? +## Unit +Needs exactly one branch. If the expression being cased on evaluates to a unit +value, evaluation will continue with the expression in that branch. +## Pair +A built-in pair expects a single branch that is a function with two arguments -, Pair, Uni +## Integer + +Casing on integers can be used for non-negative integers only, and a variable +amount of branches may be given: +``` +case e + branch_0 + branch_1 + ... + branch_n +``` +If the expression e evaluates to an integer `i`, `branch_i` will be evaluated. +If that branch is not given (or `i` is negative), execution will fail. -## Integer +Note that there is no way to provide a "catch-all" case. ## List +A `case` on built-in lists may be given one or two branches (similar to +booleans), where the first one deals with the cons case, and the second one with +the empty list. If no second branch is given, execution will fail when the list +turns out to be empty. + ## Data From e637b2e25efbfb87a9114b18f1ca853337c317f5 Mon Sep 17 00:00:00 2001 From: Jacco <4022046+basetunnel@users.noreply.github.com> Date: Fri, 21 Nov 2025 16:15:10 +0100 Subject: [PATCH 3/6] More code samples --- .../docs/delve-deeper/casing-constants.md | 130 +++++++++--------- 1 file changed, 68 insertions(+), 62 deletions(-) diff --git a/doc/docusaurus/docs/delve-deeper/casing-constants.md b/doc/docusaurus/docs/delve-deeper/casing-constants.md index 65f165b51a8..e405c95e768 100644 --- a/doc/docusaurus/docs/delve-deeper/casing-constants.md +++ b/doc/docusaurus/docs/delve-deeper/casing-constants.md @@ -2,43 +2,81 @@ sidebar_position: 26 --- +# TODO + +□ figure out how case on data will work +□ Figure out how `case ... of ...` is compiled for built-in types. +□ Run all the examples with `uplc` command line +□ Add flag name below (now named TODO) +□ test what happens in uplc if you oversaturate one of the branches of a case on +SOP (this is the main motivation of multilambdas) + # Casing on built-in types in UPLC -Starting with _intra-era hard fork_, UPLC supports a new way of processing +Starting with (HARD FORK NAME HERE), UPLC supports a new way of processing values of some built-in types, such as `Integer` and `Data`. The `case` -construct, which was originally introduced for [sums-of-products](), can also be -used to case-split on such values. +construct, originally introduced with [sums-of-products](), can also be used to +split on values of these built-in types. + +Using `case` in UPLC may improve script performance and size, for example when +dealing with `ScriptContext`, which is encoded using `Data`. Even for types like +`Bool`, it may result in smaller script size, compared to built-in functions +like `ifThenElse`. + +The currently supported built-in types that `case` supports are: + +- `unit` +- `bool` +- `integer` +- `data` +- `list` +- `pair` -Using `case` in UPLC programs can make processing of built-in types more -efficient, for example when dealing with `ScriptContext`, which is encoded using -`Data`. Even types like `Bool` +However, the branching may be subject to some constraints. For example, when +casing on `integer`, only non-negative integers can be matched and there is no +catch-all. + +In Plinth, when using the TODO flag, many standard library functions will be +compiled into UPLC's `case`, such as `fstPair`, `ifThenElse` and `caseList`. +Note that Plinth's `case ... of ...` syntax is not necessarily compiled to UPLC, +as it can sometimes be more expressive. -Depending on the built-in type, a certain order and amount of branches is -expected, and not necessarily all values can be matched using `case`. ## Bool -Booleans can be used in `case` with one or two branches, where the first is the -false branch. Boolean negation can be written as: +Booleans can be used in `case` with either one or two branches, where the first +is the `false` branch. Boolean negation can be written for example as: -``` -\b -> - case b - false - true +```uplc +lam b (case b false true) ``` -When only one branch is provided, script execution will fail when the boolean -evaluates to `true`. +When only a single branch is provided, script execution will fail when the +boolean evaluates to `true`. + +Using a single branch is appropriate when the second branch was supposed to fail +already, saving script size. ## Unit Needs exactly one branch. If the expression being cased on evaluates to a unit value, evaluation will continue with the expression in that branch. +```uplc +lam x (case x (con integer 5)) +``` + +Is a function that returns `5` if `x` evaluates to `()` without an error. + + ## Pair -A built-in pair expects a single branch that is a function with two arguments +A built-in pair expects a single branch that is a function with two arguments. +This example implements the swap function: + +```uplc +lam x (case x (lam a (lam b (con pair b a)))) +``` ## Integer @@ -53,8 +91,8 @@ case e branch_n ``` -If the expression e evaluates to an integer `i`, `branch_i` will be evaluated. -If that branch is not given (or `i` is negative), execution will fail. +If the expression `e` evaluates to an integer `i`, `branch_i` will be evaluated. +If that branch is not given (or `i` is negative), evaluation will fail. Note that there is no way to provide a "catch-all" case. @@ -65,52 +103,20 @@ booleans), where the first one deals with the cons case, and the second one with the empty list. If no second branch is given, execution will fail when the list turns out to be empty. -## Data - - +This example implements the `head` function: -# How to use built-in casing in Plinth - -Compiler flag, functions. - - -# Pattern matching and Case - -When you use pattern matching in Plinth, such as in a `case` expression, the -generated UPLC code will depend on the type of the value being matched on. - -□ Is this true or only on the UPLC level, i.e. does the compiler compile into -case or something else for built-in datatypes. For example, casing on integers -is limited to non-negative branches, and BuiltinData only to Data.Constr - -Usage in Plinth (if builtincasing flag): -(searching for BuiltinCasing) -- Bool matcher - -"built-in terms" (not built-in functions apparently, for those see below) - -- casePair (defineBuiltinTerm) -- caseList (defineBuiltinTerm) - -Built-in functions that are mapped to case instead of their built-in: -- ifThenElse -- fstPair -- sndPair -- chooseUnit - -## Case on built-in datatypes - -As of ..., pattern matching of most built-in types - -### Booleans - -### Integers +```uplc +lam xs (case xs (lam y (lam ys (y))) +``` -### BuiltinData +## Data -Only works on Data.Constr constructors +When using `case` on values of the `data` type, only `Constr` constructors can +be matched, similar to how `case` works on +[sums-of-products](./encoding#sums-of-products). -□ TODO: how will case be handled +```uplc +``` ## Algebraic datatypes From b500a9b75a064e97b6e2925c1729533d3839eee7 Mon Sep 17 00:00:00 2001 From: Jacco <4022046+basetunnel@users.noreply.github.com> Date: Tue, 9 Dec 2025 13:06:00 +0100 Subject: [PATCH 4/6] Add working example, add compiler option --- .../docs/delve-deeper/casing-constants.md | 146 ++++++++---------- .../delve-deeper/plinth-compiler-options.md | 2 +- 2 files changed, 63 insertions(+), 85 deletions(-) diff --git a/doc/docusaurus/docs/delve-deeper/casing-constants.md b/doc/docusaurus/docs/delve-deeper/casing-constants.md index e405c95e768..1b43ed78971 100644 --- a/doc/docusaurus/docs/delve-deeper/casing-constants.md +++ b/doc/docusaurus/docs/delve-deeper/casing-constants.md @@ -2,53 +2,50 @@ sidebar_position: 26 --- -# TODO +# Case-splitting on constants -□ figure out how case on data will work -□ Figure out how `case ... of ...` is compiled for built-in types. -□ Run all the examples with `uplc` command line -□ Add flag name below (now named TODO) -□ test what happens in uplc if you oversaturate one of the branches of a case on -SOP (this is the main motivation of multilambdas) +:::info -# Casing on built-in types in UPLC +This use of `case` was introduced in UPLC with protocol version 11 and requires +[Plutus Core version](../essential-concepts/versions#plutus-core-version) `1.1.0`. -Starting with (HARD FORK NAME HERE), UPLC supports a new way of processing -values of some built-in types, such as `Integer` and `Data`. The `case` -construct, originally introduced with [sums-of-products](), can also be used to -split on values of these built-in types. +::: -Using `case` in UPLC may improve script performance and size, for example when -dealing with `ScriptContext`, which is encoded using `Data`. Even for types like -`Bool`, it may result in smaller script size, compared to built-in functions -like `ifThenElse`. +In UPLC, it is possible to branch on expressions of certain built-in types, like +`Integer` and `Bool`. This can be done with `case` syntax, which is also used +for [sums-of-products](./encoding#sums-of-products). Using `case` on built-in +values may improve script performance and size. +The built-in types that `case` currently supports are: -The currently supported built-in types that `case` supports are: - -- `unit` - `bool` +- `unit` - `integer` -- `data` - `list` - `pair` -However, the branching may be subject to some constraints. For example, when +In the future, support for `data` is also planned. + +For each type, the allowed branches and their order differs. For example, when casing on `integer`, only non-negative integers can be matched and there is no -catch-all. +catch-all. See [Supported Types](#supported-types) for more detail. -In Plinth, when using the TODO flag, many standard library functions will be -compiled into UPLC's `case`, such as `fstPair`, `ifThenElse` and `caseList`. -Note that Plinth's `case ... of ...` syntax is not necessarily compiled to UPLC, -as it can sometimes be more expressive. +## Compiling to `case` in Plinth +When compiling Plinth code with the `datatypes` +[option](./plinth-compiler-options) set to `BuiltinCasing`, many standard +library functions will be compiled into this use of `case`, such as `fstPair`, +`ifThenElse` and `caseList`. Note that Plinth's `case ... of ...` syntax is not +necessarily compiled to UPLC, as it can be more expressive. -## Bool +## Supported types + +### Bool Booleans can be used in `case` with either one or two branches, where the first is the `false` branch. Boolean negation can be written for example as: ```uplc -lam b (case b false true) +lam b (case b (con bool True) (con bool False)) ``` When only a single branch is provided, script execution will fail when the @@ -57,7 +54,7 @@ boolean evaluates to `true`. Using a single branch is appropriate when the second branch was supposed to fail already, saving script size. -## Unit +### Unit Needs exactly one branch. If the expression being cased on evaluates to a unit value, evaluation will continue with the expression in that branch. @@ -69,81 +66,62 @@ lam x (case x (con integer 5)) Is a function that returns `5` if `x` evaluates to `()` without an error. -## Pair +### Pair + +A built-in pair expects a single branch: a function that takes both components +of the pair. -A built-in pair expects a single branch that is a function with two arguments. -This example implements the swap function: +This example sums the two integer constants in a pair. ```uplc -lam x (case x (lam a (lam b (con pair b a)))) +lam x (case x (lam a (lam b [(builtin addInteger) a b]))) ``` -## Integer +### Integer Casing on integers can be used for non-negative integers only, and a variable -amount of branches may be given: +amount of branches may be given. If the expression `e` evaluates to an integer +`i`, the `i`th branch will be evaluated. If there is no branch, `case` will fail. + +For example, the following expression evaluates to `con string "c"` ``` -case e - branch_0 - branch_1 - ... - branch_n +case [(builtin addInteger) (con integer 1) (con integer 1)] + (con string "a") + (con string "b") + (con string "c") ``` -If the expression `e` evaluates to an integer `i`, `branch_i` will be evaluated. -If that branch is not given (or `i` is negative), evaluation will fail. +If the `i`th branch is not given, or `i` is a negative integer, evaluation will +fail: + +``` +case [(builtin addInteger) (con integer 2) (con integer 2)] + (con string "a") + (con string "b") + (con string "c") +``` + +Results in + +``` +An error has occurred: +'case' over a value of a built-in type failed with +'case 4' is out of bounds for the given number of branches: 3 +Caused by: 4 +``` Note that there is no way to provide a "catch-all" case. -## List +### List A `case` on built-in lists may be given one or two branches (similar to booleans), where the first one deals with the cons case, and the second one with the empty list. If no second branch is given, execution will fail when the list turns out to be empty. -This example implements the `head` function: - -```uplc -lam xs (case xs (lam y (lam ys (y))) -``` - -## Data - -When using `case` on values of the `data` type, only `Constr` constructors can -be matched, similar to how `case` works on -[sums-of-products](./encoding#sums-of-products). +This example implements the `head` function, which fails if the list if empty. ```uplc +lam xs (case xs (lam y (lam ys y))) ``` - - -## Algebraic datatypes - -Datatypes defined using `data` can be compiled with different encodings (see -[Encoding Data Types in UPLC](./encoding)). Consequently, a `case` expression in -Plinth will generate different UPLC. - -### SOP Encoding (Sums-of-products) - -This is the default for ADTs. The resulting UPLC will uses UPLC's `case` syntax, see the [SOP example](./encoding#sums-of-products). - -### Scott Encoding - -When enabling this encoding, the resulting UPLC will use a polymorphic matching -function of the Scott encoding, see the [Scott Encoding -example](encoding#scott-encoding). - - - -# GHC's pattern match compiler - -Plinth supports for most pattern matching features of GHC, because it uses GHC's -desugaring pass. Complex patterns are generally transformed into nested `case` -expressions. The general algorithm for compiling pattern matching is described -in [The Implementation of Functional Programming Languages, Chapter -4](https://www.microsoft.com/en-us/research/wp-content/uploads/1987/01/slpj-book-1987-small.pdf). -More detail about language extensions regarding pattern matching can be found in -the [GHC User -Guide](https://ghc.gitlab.haskell.org/ghc/doc/users_guide/exts/patterns.html). diff --git a/doc/docusaurus/docs/delve-deeper/plinth-compiler-options.md b/doc/docusaurus/docs/delve-deeper/plinth-compiler-options.md index d4fc3c06704..b0e8ecb0038 100644 --- a/doc/docusaurus/docs/delve-deeper/plinth-compiler-options.md +++ b/doc/docusaurus/docs/delve-deeper/plinth-compiler-options.md @@ -26,7 +26,7 @@ For each boolean option, you can add a `no-` prefix to switch it off, such as `n |`coverage-all`|Bool|False|Add all available coverage annotations in the trace output| |`coverage-boolean`|Bool|False|Add boolean coverage annotations in the trace output| |`coverage-location`|Bool|False|Add location coverage annotations in the trace output| -|`datatypes`|DatatypeCompilationOpts|SumsOfProducts|Set datatype encoding style| +|`datatypes`|DatatypeCompilationOpts|SumsOfProducts|BuiltinCasing|Set datatype encoding style| |`defer-errors`|Bool|False|If a compilation error happens and this option is turned on, the compilation error is suppressed and the original Haskell expression is replaced with a runtime-error expression.| |`dump-compilation-trace`|Bool|False|Dump compilation trace for debugging| |`dump-pir`|Bool|False|Dump Plutus IR| From 2db9f8c774b7ba40f76a85f34fcc616037e4c6b6 Mon Sep 17 00:00:00 2001 From: Jacco <4022046+basetunnel@users.noreply.github.com> Date: Tue, 9 Dec 2025 13:20:00 +0100 Subject: [PATCH 5/6] Typos --- .../docs/delve-deeper/casing-constants.md | 34 +++++++++---------- 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/doc/docusaurus/docs/delve-deeper/casing-constants.md b/doc/docusaurus/docs/delve-deeper/casing-constants.md index 1b43ed78971..c06b43d35d9 100644 --- a/doc/docusaurus/docs/delve-deeper/casing-constants.md +++ b/doc/docusaurus/docs/delve-deeper/casing-constants.md @@ -6,8 +6,9 @@ sidebar_position: 26 :::info -This use of `case` was introduced in UPLC with protocol version 11 and requires -[Plutus Core version](../essential-concepts/versions#plutus-core-version) `1.1.0`. +This use of `case` in UPLC was introduced with protocol version 11 and requires +[Plutus Core version](../essential-concepts/versions#plutus-core-version) +`1.1.0`. ::: @@ -25,31 +26,30 @@ The built-in types that `case` currently supports are: In the future, support for `data` is also planned. -For each type, the allowed branches and their order differs. For example, when -casing on `integer`, only non-negative integers can be matched and there is no -catch-all. See [Supported Types](#supported-types) for more detail. +For each type, the allowed branches and their order differs. See [Supported +Types](#supported-types) for more detail. ## Compiling to `case` in Plinth -When compiling Plinth code with the `datatypes` -[option](./plinth-compiler-options) set to `BuiltinCasing`, many standard -library functions will be compiled into this use of `case`, such as `fstPair`, -`ifThenElse` and `caseList`. Note that Plinth's `case ... of ...` syntax is not -necessarily compiled to UPLC, as it can be more expressive. +When compiling Plinth code with the [option](./plinth-compiler-options) +`datatypes=BuiltinCasing`, many standard library functions will be compiled into +this use of `case`, such as `fstPair`, `ifThenElse` and `caseList`. Note that +Plinth's `case ... of ...` syntax is not necessarily compiled to UPLC, as it can +be more expressive. ## Supported types ### Bool Booleans can be used in `case` with either one or two branches, where the first -is the `false` branch. Boolean negation can be written for example as: +is the `False` branch. Boolean negation can be written for example as: ```uplc lam b (case b (con bool True) (con bool False)) ``` When only a single branch is provided, script execution will fail when the -boolean evaluates to `true`. +boolean evaluates to `True`. Using a single branch is appropriate when the second branch was supposed to fail already, saving script size. @@ -57,15 +57,13 @@ already, saving script size. ### Unit Needs exactly one branch. If the expression being cased on evaluates to a unit -value, evaluation will continue with the expression in that branch. +value, evaluation will continue with the expression in that branch. For example, +this expression evaluates to `con integer 5`. ```uplc -lam x (case x (con integer 5)) +case (con unit ()) (con integer 5) ``` -Is a function that returns `5` if `x` evaluates to `()` without an error. - - ### Pair A built-in pair expects a single branch: a function that takes both components @@ -111,7 +109,7 @@ An error has occurred: Caused by: 4 ``` -Note that there is no way to provide a "catch-all" case. +Note that there is no way to provide a "catch-all" case for integers. ### List From e2603d9c719e0dca512e2fce49017ea3622e295d Mon Sep 17 00:00:00 2001 From: Jacco <4022046+basetunnel@users.noreply.github.com> Date: Wed, 7 Jan 2026 17:12:11 +0100 Subject: [PATCH 6/6] Include info about why the new flag is better than not using built-in case --- .../docs/delve-deeper/casing-constants.md | 52 +++++++++++++++++-- 1 file changed, 48 insertions(+), 4 deletions(-) diff --git a/doc/docusaurus/docs/delve-deeper/casing-constants.md b/doc/docusaurus/docs/delve-deeper/casing-constants.md index c06b43d35d9..efa37ddf2b4 100644 --- a/doc/docusaurus/docs/delve-deeper/casing-constants.md +++ b/doc/docusaurus/docs/delve-deeper/casing-constants.md @@ -32,10 +32,11 @@ Types](#supported-types) for more detail. ## Compiling to `case` in Plinth When compiling Plinth code with the [option](./plinth-compiler-options) -`datatypes=BuiltinCasing`, many standard library functions will be compiled into -this use of `case`, such as `fstPair`, `ifThenElse` and `caseList`. Note that -Plinth's `case ... of ...` syntax is not necessarily compiled to UPLC, as it can -be more expressive. +`datatypes=BuiltinCasing` (which in the future be achieved with +`datatypes=SumsOfProducts), many standard library functions will be compiled +into this use of `case`, such as `fstPair`, `ifThenElse` and `caseList`. Note +that Plinth's `case ... of ...` syntax is not necessarily compiled to UPLC, as +it can be more expressive. ## Supported types @@ -54,6 +55,18 @@ boolean evaluates to `True`. Using a single branch is appropriate when the second branch was supposed to fail already, saving script size. + +:::info + +When compiling without `datatypes=BuiltinCasing`, Plinth's `ifThenElse` is +compiled into UPLC's `ifThenElse` built-in function, which usually requires more +AST nodes since each branch argument needs to be delayed (function application is +strict), and finally force the chosen branch. This impacts the size and +execution cost. + +::: + + ### Unit Needs exactly one branch. If the expression being cased on evaluates to a unit @@ -75,6 +88,14 @@ This example sums the two integer constants in a pair. lam x (case x (lam a (lam b [(builtin addInteger) a b]))) ``` +:::info + +When compiling without `datatypes=BuiltinCasing`, Plinth's `choosePair` is +compiled into multiple built-in function calls to project out the pair's +components, impacting size and execution cost. + +::: + ### Integer Casing on integers can be used for non-negative integers only, and a variable @@ -111,6 +132,20 @@ Caused by: 4 Note that there is no way to provide a "catch-all" case for integers. +:::info + +In Plinth, using `caseInteger` with `datatypes=BuiltinCasing` will be compiled into +the above `case` construct in PIR, provided the second argument is given as a +literal list (otherwise this is a compile error). + +When not using `datatypes=BuiltinCasing`, Plinth's `caseInteger` is compiled +into a much less efficient implementation that turns the second argument in a +list (of which the representation depends on the chosen `datatypes=` flag), and +does a recursive lookup in that list. + +::: + + ### List A `case` on built-in lists may be given one or two branches (similar to @@ -123,3 +158,12 @@ This example implements the `head` function, which fails if the list if empty. ```uplc lam xs (case xs (lam y (lam ys y))) ``` + +:::info + +When compiling without `datatypes=BuiltinCasing`, Plinth's `caseList` is +compiled into a combination of built-in calls such as `chooseList`, `headList` +and `tailList`. Similarly to booleans, the branches are also thunked, impacting +script size and execution cost. + +:::