Skip to content

CIP-0194? | Plutus Core builtin matchDataConstr - #1236

Open
SeungheonOh wants to merge 9 commits into
cardano-foundation:masterfrom
SeungheonOh:sho/builtinMatching
Open

CIP-0194? | Plutus Core builtin matchDataConstr#1236
SeungheonOh wants to merge 9 commits into
cardano-foundation:masterfrom
SeungheonOh:sho/builtinMatching

Conversation

@SeungheonOh

@SeungheonOh SeungheonOh commented Jul 31, 2026

Copy link
Copy Markdown

Proposal for adding a new UPLC AST node: Match. Match enables matching complex and nested builtin value structure, namely Data values like script context, without builtin function invocation overhead.

A working prototype has been implemented: IntersectMBO/plutus#7852

Rendered

@rphair rphair changed the title builtin matching on UPLC CIP-???? | Builtin pattern matching in UPLC Jul 31, 2026

@rphair rphair left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@SeungheonOh thanks very much for documenting your implementation with a CIP. The in-progress work I think makes it definite we would assign a CIP number in Triage at the next CIP meeting (https://hackmd.io/@cip-editors/140).

@zliu41 @ana-pantilie @colll78 @Quantumplation @fallen-icarus if you could review the CIP technical presentation any time before or after its confirmation, that would be great.

@kwxm it looks like performance is already also well documented here, but please likewise feel free to contribute about that presentation as well.

Comment thread CIP-builtin-matching/README.md Outdated
@rphair rphair added Category: Plutus Proposals belonging to the 'Plutus' category. State: Triage Applied to new PR afer editor cleanup on GitHub, pending CIP meeting introduction. labels Jul 31, 2026
@colll78

colll78 commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

Strongly support this CIP, approach is sound and a massive improvement.

Comment thread CIP-builtin-matching/README.md Outdated

### Costing

All work performed by `Match` is charged incrementally. Matching steps are divided into four CEK step kinds:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is rather different to how costing works for other terms, where a cost is associated with the reduction rule for a term.

Here we either have one very big reduction rule, or we would need a way to evaluate the match incrementally. But the possibility of backtracking in the matching makes this difficult.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As implemented, latter is the case. Match is being costed incrementally. Backtracking doesn't really pose any issue since it also increments the costs for failed cases, so it doesn't have to do anything complicated for failed branches.

I wrote this in a confusing way. Not all four steps being proposed are CEK steps. Only one is for CEK itself, and other three are steps used within the matcher.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Backtracking doesn't really pose any issue since it also increments the costs for failed cases, so it doesn't have to do anything complicated for failed branches.

Backtracking makes it harder to give an incremental reduction behaviour. Perhaps we still could - if we eliminate a branch then we can remove it from the match.

Comment thread CIP-builtin-matching/README.md Outdated

### Evaluation

`Match` is evaluated as follows:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would like to see a more declarative and less operational description of how this works. Typically we give a reduction rule for terms.

Comment thread CIP-0194/README.md Outdated
| DefaultPatternFieldsPrefixWildcard
| DefaultPatternFieldsPrefixCapture

data DefaultBuiltinPattern

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a lot of syntax. Probably this increases the size of the base language by 30%+!

Comment thread CIP-builtin-matching/README.md Outdated
2. If the result is not a builtin constant, evaluation fails. Otherwise, inspect alternatives in source order.
3. Match an alternative depth-first, from left to right, recording captures as they are reached.
4. On a mismatch, discard that alternative's pending work and captures, then try the next alternative.
5. On success, select that alternative's handler and apply the captured values to it in source order.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are the handlers evaluated strictly before evaluating the match?

@SeungheonOh SeungheonOh Aug 3, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, none but the matching handler will be evaluated. Only patterns that comes before the matching case will be inspected.

I'll try to clarify this section

For example:

(match (con integer 2)
  (pattern (integer 0) (error)) -- Pattern inspected, but not evaluated
  (pattern (integer 1) <expensive work>) -- Pattern inspected, but not costed/evaluated
  (pattern (integer 2) (con integer 42))
  (pattern (integer 3) (error)))

-- > (con integer 42)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That seems fine, it mirrors case.

Comment thread CIP-0194/README.md Outdated
Comment thread CIP-0194/README.md Outdated
Comment thread CIP-0194/README.md Outdated

#### A dedicated `Let` term

A `Let` term could bind a row of values but still requires CEK support for that row and overlaps with lambda/application as a binding mechanism. Like multi-lambda, it does not provide general nested matching.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, this seems orthogonal

Comment thread CIP-0194/README.md Outdated

The following local benchmarks compare `Match` with existing deconstruction using partial builtins, optionally guarded by `chooseData`, or builtin `Case`. They measure CEK wall-clock time rather than calibrated on-chain execution units.

#### Capturing one deeply positioned value

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So... why is this faster? Operationally speaking. We are fundamentally doing a very similar process. Is it just that we skip some expensive parts of the builtin machinery? It seems odd that we're able to do the same thing but faster!

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's mainly the builtin calling overhead. Calling builtin requires several extra CEK frames. In most cases, it needs Apply and Builtin and for some it also requires extra Forces. These need to happen per each layer of nested values and these overheads turns out to be more expensive than actually deconstructing values themselves.

Match removes all of the overhead only running on very lean pattern syntax and doing value deconstruction directly removing significant amount of the overhead. This is exactly the same reason why IfThenElse is slower(almost 80% iirc!) than Case when casing on boolean.

Also, Match gives options to match pattern without capturing value, this reduces CEK steps even more. For instance, if you just want to check if D.I 10 is integer data or not, currently, you'd do chooseData (D.I 10) ... (\i -> ...) ... where builtin not only have to match on the Data constructors, but it also have to capture 10 and apply to the handler even though the value is not needed. This also incurs more extraneous cost. Match on the other hand can do (pattern (data-i (wildcard) <arity 0>) which doesn't have to dispatch apply at all. This is why the performance gap is bigger when fewer captures were performed in the benchmarks

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, we still need to do the work of evaluating arguments and applying them to functions. Are we just not book-keeping that on the stack?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If doing it all in one go is what helps, then maybe we really do need to compare this to multi-lambdas and multi-application.

Comment thread CIP-builtin-matching/README.md Outdated
`Match` is evaluated as follows:

1. Evaluate the scrutinee.
2. If the result is not a builtin constant, evaluation fails. Otherwise, inspect alternatives in source order.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we allow matching on other values? Notably, what about con values? If we're going to add pattern-matching it's a shame not to get it on datatype values.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean Constrs? I didn't add it because I initially thought it could break typing in TLPC/PIR. However, looking again, it seems reasonable to add something like DefaultPatternConstr Word64 (Vector DefaultBuiltinPattern).

I'm not entirely sure performance implication to adding this. This would definitely complicate the implementation(which can consequently make it slower) because having pattern for Term.Constr means now it needs to carry and match on Term not just values.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Constrs are a kind of value, though?

Comment thread CIP-0194/README.md Outdated
| DefaultPatternByteString !ByteString
| DefaultPatternBool !Bool
| DefaultPatternUnit
| DefaultPatternList

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not?

DefaultPatternList { headPattern :: DefaultBuiltinPattern, tailPattern :: DefaultBuiltinPattern }

you'd need DefaultPatternNil, perhaps, to terminate them. But I'm a bit unsure about using this prefix/exact shape descriptor rather than a pattern AST that follows the shape of the datatypes.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would make pattern interpretation slower since for matching long list, it would need to match on DefaultPatternList repeatedly. I figure it's better to prefer structure that is more optimal to run since this won't be user facing interface anyways.

@wadler

wadler commented Aug 3, 2026

Copy link
Copy Markdown

The structure is odd compared to the usual pattern matching. Your form:

(match scrutinee (pattern pair (pair (bind) (bind)) (bind))) (lam x (lam y (lam z body))))

Usual form:

(match scrutinee (pattern pair (pair x y) z)) body)

In both cases, the body refers to x, y, z as bound variables.

The first form reuses the existing lambda machinery, while the second does not, so I guess the first is slightly easier to implement. But nowhere is the usual form mentioned or compared with. I think there is good reason to believe that the second can be implemented more efficiently (although it may take more work to do so). So a comparison is essential.

Typically, a compiler gets rid of nested pattern matching and only uses a shallow case to look at the top-level structure. Your motivation is that the existing mechanism which does this can (if misused) lead to partial applications, but an easier way to fix that is to supply an arity with each case rather than nested pattern matching. Did you compare with that alternative? You need to add this comparison the the CEP to justify the design.

Michael noted that for lists matching on cons and nil instead of prefix is standard. Sungheon responded that the prefix design is more efficient, which sounds plausible. But this needs to be documented with performance numbers in the CEP.

If match is included it should also apply to sum-of-product types. (I think Michael makes a similar point.)

@rphair rphair changed the title CIP-???? | Builtin pattern matching in UPLC CIP-0194? | Builtin pattern matching in UPLC Aug 4, 2026

@rphair rphair left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@SeungheonOh this was declared a candidate at the CIP meeting today, continuing the prior confirmations. Going forward we will generally await the settlement of current & future review like what @michaelpj has already provided (please "resolve" the points that seem to be settled, since this might not always be clear to editors).

Once generally settled please feel free to explicitly point this out in a comment, so we can make sure it moves on to final / editorial review. In the meantime please rename the containing directory to CIP-0194 and update the "Rendered" link in your OP. 🎉

Comment thread CIP-builtin-matching/README.md Outdated
@rphair rphair added State: Confirmed Candiate with CIP number (new PR) or update under review. and removed State: Triage Applied to new PR afer editor cleanup on GitHub, pending CIP meeting introduction. labels Aug 4, 2026
@SeungheonOh

SeungheonOh commented Aug 5, 2026

Copy link
Copy Markdown
Author

Thank you, @wadler and @michaelpj, for the review!

About binding captures directly

It seems that a similar design was considered when SOP terms were added in CIP-85, but was ultimately not adopted. CIP-85 mentions that this optimization initially produced an improvement of around 10%. However, another optimization reduced the realized improvement from direct binding to only around 3%, which was considered a small enough difference to justify preferring the simpler implementation.

I am not sure exactly what that other optimization was, or whether there were additional reasons for not using direct binding in CIP-85. Maybe @michaelpj can provide more context here.

I tested direct binding for Match as well, and observed an approximately 10–15% improvement in execution time. Unlike the proposal discussed in CIP-85, this does not require a new alt annotation specifying the arity of each handler, because the pattern syntax already determines how many variables are bound. This appears to be a worthwhile optimization, even considering the additional complications for TPLC and PIR. I will include the experiment in the CIP and pursue this approach.

About (re)using Case with arity/pattern attached to each handler

Initially, I found this to be the most straightforward change with the smallest UPLC footprint. It would have looked something like this:

(case (con data (Constr 0 [I 1, List [I 2, I 3]]))
  (pattern (data-constr 0 (bind) (wildcard)) (lam x ...)))

-- `pattern` itself is a new AST node: `Pattern pat term`.
-- Having `pattern` as a standalone AST node would also allow it
-- to be used independently of `Case`, as a partially defined
-- pattern-matching function:

[(pattern (data-constr 0 (bind) (wildcard)) (lam x ...))
 (con data ...)]
-- We can use direct bind here too and it would look even more natural:
[(pattern (data-constr 0 x (wildcard)) x)
 (con data ...)]

-- If we are only attaching arity, it would look like

(case (con data (Constr 0 [I 1, List [I 2, I 3]]))
  (arity 2 (lam x y ...))   -- Constr 0
  (arity 3 (lam x y z...))) -- Constr 1

-- Unlike `pattern`, this would not allow skipping constr 
-- indices (for example, only matching on `Data.Constr 2`) and 
-- would force all elements of the list to be bound. 

This would allow Case to be reused for pattern matching, while pattern could also function independently as a pattern-matching lambda.

Unfortunately, there are few issues with this approach.

First, the CEK machine does not evaluate the branch handlers of a Case node until a branch has been selected. Associating a pattern—or even only an arity—with each handler would therefore require the machine to inspect the AST of each branch before selecting one. I have not benchmarked this design(let alone implement), so I cannot make any claim, but inspecting AST nodes outside the CEK machine's main compute/return loop generally has a negative performance impact. This idea was discarded early on because of this concern.

Second, supporting general patterns through Case would conflict with the existing casing behavior for builtin constants. Cases over lists, integers, and booleans currently use fixed branch positions. Supporting examples such as the following would therefore require the existing builtin casing mechanism to be deprecated:

(case (con (list integer) [1, 2, 3])
  (pattern (list (bind) (wildcard) (bind)) ...)
  (pattern (list (bind) (wildcard)) ...))

Alternatively, case would need to determine whether it was operating in pattern-matching mode or conventional casing mode, but this sounds like a nightmare. Deprecation of existing builtin casing behavior may not be a decisive problem though, since introducing new Pattern node already requires a language-version bump, allowing the older builtin constant casing behavior to be deprecated smoothly.

Lastly, using Case for arbitrary patterns(even shallow) would need costing mechanism of Case to be changed. I don't think this is a big blocker; it should be relatively straightforward. However, it requires changing how costing behaves in existing Case node which might not be favorable.

I haven't explored this options deeply. Please let me know if this approach is more natural and is worthwhile to test out. I discarded this idea rather early on, so some(or all) of the issues I mentioned might not even be an issue at all.

About shallow matching

I implemented shallow matching and benchmarked it against matching the same nested structures directly. Contrary to my initial expectation, nested matching did not provide a significant performance improvement over shallow matching.

Neither approaches are uniformly faster. The differences were generally within approximately 10% of CPU execution time. Shallow matching performed better for wider structures, whereas nested matching performed better when matching values deeply within heavily nested structures.

I spent some time to figure out how to cost nested patterns and it turned out to be very difficult to come up with one that won't overshoot all pattern types. This is unlike Shallow matching which provides a substantially more straightforward costing model as it does not need any of the incremental costing mechanism.For simplicity of costing and competitive performance, shallow matching seems to be a better direction. I will collect additional benchmark data and update the CIP to use shallow matching instead.

@zliu41 zliu41 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I need to review it in more detail, but here are some initial comments:

  • It's worth elaborating why "A handler with the wrong number of arguments may therefore partially apply instead of failing" is problematic
  • The baseline in your benchmark should use the new dropList builtin, if not already
  • It would be interesting to know how much this approach narrows the performance gap between Data encoding and SOP encoding. Can it close the gap entirely? If not, why?

@zliu41

zliu41 commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Regarding the long list of patterns, I'd suggest shortening them as much as you can.

  • The vast majority of data types are encoded using Constr and List. Optimizing for these two should deliver most of the value.
  • DefaultPatternByteString: the usefulness is unclear. And it also needs an equalsByteString-like cost model, which adds complexity.
  • DefaultPatternBool can already be expressed with casing on Bool.
  • DefaultPatternInteger: why only Int64? Is it to make costing easier? But DefaultPatternByteString already requires a complex costing mechanism. And its usefulness is unclear.
  • DefaultPatternDataI and DefaultPatternDataB: the usefulness is unclear.
  • Your pattern language allows expressing patterns that make no sense, such as DefaultPatternDataI (DefaultPatternByteString "foo").

@ana-pantilie

ana-pantilie commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

What is the reason behind delegating variable binding to the handler instead of using a matching mechanism which constructs substitution contexts?

Concretely, if I understand this correctly, in the following example:

match scrutinee
  (pair capture capture)
  handler

handler needs to be of the form \x -> \y -> body. If it's not, then by the typing rules in this CIP, the program is not a valid TPLC program. One consequence is a new class of potentially "ill-formed" programs in UPLC, since UPLC is untyped.

However, if match also introduced a substitution context, for example:

match scrutinee
  (pattern (pair (var x) (var y)))
  handler

Then it would be up to the matching algorithm to produce a valid substitution for x and y, there's no more requirement for the handler to be of a specific form. That would, of course, require the algorithm to produce fresh variables in the context in order to avoid shadowing.

I think it would also make matching more expressive:

(\scrut -> 
  match scrut
    (pattern (pair (var x) (var x)))
    handler
) (1, 2)

After beta-reduction, the matching algorithm would not be able to find a valid substitution for x, therefore the program would not continue execution at that stage. Otherwise, in the current proposed design, a user would have to manually check inside the handler that x == y, which might be more expensive since there's another builtin function call involved.

Of course, my suggestion would require a more complex costing mechanism to account for the substitution construction. But I think that using a proper matching algorithm would make it more future proof, in case we want to add new features to match in the future.

Comment thread CIP-0194/README.md Outdated

where $M$ is the scrutinee, $p_i$ is a universe-specific builtin pattern, and $H_i$ is its handler. The alternatives are ordered.

A builtin constant is written $C=\langle u,v\rangle$, pairing a universe tag $u$ with a value $v:\mathsf{El}(u)$. The UPLC constant term containing $C$ is written $\ulcorner C\urcorner$. A capture sequence is written $\overline C=[C_1,\ldots,C_k]$, and $\epsilon$ is the empty sequence. Sequence concatenation is $\mathbin{+\!+}$.

@kwxm kwxm Aug 13, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All occurrences of $\mathbin{+\!+}$ renders (at least on GitHub) as +! +, which is surely not what's intended.

Image

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You would be far ahead of me in LaTeX maths but I understand this expression will simply render the argument of \mathbin in a typeface consistent with other math. It therefore is doing what I would expect it to do: what were you intending?

A previewer shows the same thing, with a little difference in horizontal spacing: https://quicklatex.com

@kwxm kwxm Aug 14, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In LaTeX the \! represents a small negative space, moving the two +s closer together. I think this is suppose to render as ++, maybe with no space in the middle.

I have no idea how to fix it though. Markdown renderers seem to be a bit inconsistent.

@rphair rphair Aug 14, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks; I don't know why I thought a literal ! was coming out in the markup from the previewer before... I can't see it there now. Indeed it looks there like the + signs are conjoined and I can see now what you were getting at. Maybe:

  • some more of these maths presentation issues would be documented on https://github.com/github/markup/issues like the one below (or you could ask there);
  • I can do a quick poll at the CIP meeting to see if any maths formatting enthusiasts have anything to suggest.

Comment thread CIP-0194/README.md

the matching function returns

$$

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't render properly:

Image

@rphair rphair Aug 13, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This renders properly on that previewer

ql_a72f65b627214934d0c9c0523e1bdfab_l3

... so at least one thing is working differently here on GitHub. @michaelpj what do you think?

@rphair rphair Aug 13, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

p.s. @kwxm maybe escaping the # character will fix it on GitHub?

Comment thread CIP-0194/README.md Outdated

### Backward compatibility

The change is backward-compatible at the Plutus Core language level because `Match` is guarded by a new minor language version. Scripts using earlier versions continue to parse and evaluate with unchanged semantics.

@kwxm kwxm Aug 13, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bear in mind that data will probably be getting an extra value constructor [in Plutus V4](https://github.com/zliu41/CIPs/blob/v4/CIP-0195/README.md#list-vs-array.. I think we can make that backward compatible with the current version of data using a semantic variant. Presumably the stuff described in this CIP would need to be extended to work with the new version, and only the new version. Would that cause any extra difficulty?

@SeungheonOh

Copy link
Copy Markdown
Author

I explored achieving similar matching performance with a builtin function instead of introducing a dedicated Match AST node, and the builtin appears to be the better direction.
The benchmarks show competitive improvements over traditional Data.Constr deconstruction, without adding another core term that substantially overlaps with Case. A native Match term is still faster for some shapes, but it also requires new syntax, Flat encoding, scoping rules, evaluator frames, machine-cost events, optimizer support, and conformance rules.

The builtin design also moves most of the static complexity into PLC. PLC validates the matching description and determines its result SOP type. After erasure, UPLC receives an ordinary ByteString and evaluates it through the existing builtin machinery, returning a VConstr for dispatch by Case. This preserves structural erasure and avoids adding new pattern or binding machinery to UPLC.

The current costing parameter for the builtin and Match prototypes, I don't think, is fully accurate yet. The execution budget comparison is only for approximation while CEK Wall time gives better understanding of how each performs. I should point out the builtin approach gives much easier costing in general with smaller costing overhead; costing function is directly related to the Bytestring pattern encoding. Match nodes on the other hand require additional costing mechanism specialized to the new AST node itself much is very challenging to tune in.

@SeungheonOh

Copy link
Copy Markdown
Author

@rphair I made big changes that basically removes most content from the original proposal in favor of new approach. I wasn't sure if it needed a new CIP PR or not so I just updated this one. The changes are still on topic of making Data faster to match and since we will only implement one of different approaches explored so far, I prefer to keep everything in CIP-194. Please let me know if we need to create a new proposal.

@rphair rphair left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(@SeungheonOh I'm editing my comments in here since my last review crossed your own last posting above)

The scope of this CIP is still to achieve what was originally imagined & we see many cases like that over the course of a CIP PR lifetime. So there is absolutely no necessity (and, I believe, no advantage) in requiring a new PR for this. 😎

Comment thread CIP-0194/README.md Outdated
@SeungheonOh
SeungheonOh force-pushed the sho/builtinMatching branch 2 times, most recently from 4f6d9c8 to ff08f20 Compare August 17, 2026 19:26
Co-authored-by: Robert Phair <rphair@cosd.com>
@rphair rphair changed the title CIP-0194? | Builtin pattern matching in UPLC CIP-0194? | Plutus Core builtin matchDataConstr Aug 17, 2026
@SeungheonOh

Copy link
Copy Markdown
Author

We've implemented IntersectMBO/plutus#7914 which is related to this CIP. This PRs adds casing Data.Constr directly using existing Case node without adding new AST node Match. I haven't considered this approach originally since last time I checked before the addition of DropList this did not significantly improved performance as most of the cost came from matching the body part of the Data.Constr. However, with DropList having this almost gives 30%~50% improvements on many scripts since matching body parts accounts for less budget thanks for drop list.

As this change uses existing casing mechanism and doesn't add any new mechanism, it is completely independent of different ideas proposed in this CIP. Match approach in this CIP would still give additional performance improvements(around additional 50% in execution budgets and more on actual execution time), so this CIP will be kept open and we will continue to persue ideas here

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Category: Plutus Proposals belonging to the 'Plutus' category. State: Confirmed Candiate with CIP number (new PR) or update under review.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants