Skip to content

Conversation

@SeungheonOh
Copy link
Collaborator

Part of #6602

We haven't fully decided how casing on list should be. I tried simply casing into nil case and cons case.

@SeungheonOh
Copy link
Collaborator Author

/benchmark lists

@SeungheonOh SeungheonOh added No Changelog Required Add this to skip the Changelog Check and removed No Changelog Required Add this to skip the Changelog Check labels Jul 7, 2025
@github-actions
Copy link
Contributor

github-actions bot commented Jul 7, 2025

PR Preview Action v1.6.2

🚀 View preview at
https://IntersectMBO.github.io/plutus/pr-preview/pr-7188/

Built to branch gh-pages at 2025-07-14 13:33 UTC.
Preview will be ready when the GitHub Pages deployment is complete.

@github-actions
Copy link
Contributor

github-actions bot commented Jul 7, 2025

Click here to check the status of your benchmark.

@github-actions
Copy link
Contributor

github-actions bot commented Jul 7, 2025

Comparing benchmark results of 'lists' on '837a15684' (base) and '5ac006c50' (PR)

Results table
Script 837a156 5ac006c Change
sort/ghcSort/50 140.1 μs 136.3 μs -2.7%
sort/ghcSort/100 323.3 μs 313.9 μs -2.9%
sort/ghcSort/150 559.6 μs 539.2 μs -3.6%
sort/ghcSort/200 751.1 μs 724.9 μs -3.5%
sort/ghcSort/250 975.9 μs 944.7 μs -3.2%
sort/ghcSort/300 1.278 ms 1.242 ms -2.8%
sort/insertionSort/50 442.2 μs 439.7 μs -0.6%
sort/insertionSort/100 1.777 ms 1.762 ms -0.8%
sort/insertionSort/150 3.978 ms 3.964 ms -0.4%
sort/insertionSort/200 7.124 ms 7.072 ms -0.7%
sort/insertionSort/250 11.16 ms 11.09 ms -0.6%
sort/insertionSort/300 16.16 ms 16.07 ms -0.6%
sort/mergeSort/50 439.4 μs 429.8 μs -2.2%
sort/mergeSort/100 1.011 ms 991.3 μs -1.9%
sort/mergeSort/150 1.637 ms 1.597 ms -2.4%
sort/mergeSort/200 2.284 ms 2.233 ms -2.2%
sort/mergeSort/250 3.011 ms 2.942 ms -2.3%
sort/mergeSort/300 3.669 ms 3.594 ms -2.0%
sort/quickSort/50 1.107 ms 1.053 ms -4.9%
sort/quickSort/100 4.671 ms 4.420 ms -5.4%
sort/quickSort/150 10.51 ms 10.03 ms -4.6%
sort/quickSort/200 18.67 ms 17.66 ms -5.4%
sort/quickSort/250 29.24 ms 28.03 ms -4.1%
sort/quickSort/300 42.31 ms 40.47 ms -4.3%
sum/compiled-from-Haskell/sum-right-builtin/100 82.56 μs 80.69 μs -2.3%
sum/compiled-from-Haskell/sum-right-builtin/500 431.4 μs 421.1 μs -2.4%
sum/compiled-from-Haskell/sum-right-builtin/1000 924.8 μs 907.8 μs -1.8%
sum/compiled-from-Haskell/sum-right-builtin/2500 2.826 ms 2.773 ms -1.9%
sum/compiled-from-Haskell/sum-right-builtin/5000 6.120 ms 6.003 ms -1.9%
sum/compiled-from-Haskell/sum-right-Scott/100 45.55 μs 44.90 μs -1.4%
sum/compiled-from-Haskell/sum-right-Scott/500 240.6 μs 239.4 μs -0.5%
sum/compiled-from-Haskell/sum-right-Scott/1000 530.3 μs 523.4 μs -1.3%
sum/compiled-from-Haskell/sum-right-Scott/2500 1.860 ms 1.833 ms -1.5%
sum/compiled-from-Haskell/sum-right-Scott/5000 4.300 ms 4.233 ms -1.6%
sum/compiled-from-Haskell/sum-right-data/100 232.5 μs 226.8 μs -2.5%
sum/compiled-from-Haskell/sum-right-data/500 1.270 ms 1.236 ms -2.7%
sum/compiled-from-Haskell/sum-right-data/1000 2.896 ms 2.826 ms -2.4%
sum/compiled-from-Haskell/sum-right-data/2500 7.806 ms 7.647 ms -2.0%
sum/compiled-from-Haskell/sum-right-data/5000 16.55 ms 16.24 ms -1.9%
sum/compiled-from-Haskell/sum-left-builtin/100 83.61 μs 79.77 μs -4.6%
sum/compiled-from-Haskell/sum-left-builtin/500 426.6 μs 407.0 μs -4.6%
sum/compiled-from-Haskell/sum-left-builtin/1000 918.6 μs 881.5 μs -4.0%
sum/compiled-from-Haskell/sum-left-builtin/2500 2.804 ms 2.706 ms -3.5%
sum/compiled-from-Haskell/sum-left-builtin/5000 6.193 ms 5.955 ms -3.8%
sum/compiled-from-Haskell/sum-left-Scott/100 45.88 μs 43.64 μs -4.9%
sum/compiled-from-Haskell/sum-left-Scott/500 245.8 μs 233.6 μs -5.0%
sum/compiled-from-Haskell/sum-left-Scott/1000 535.6 μs 515.6 μs -3.7%
sum/compiled-from-Haskell/sum-left-Scott/2500 1.824 ms 1.771 ms -2.9%
sum/compiled-from-Haskell/sum-left-Scott/5000 4.280 ms 4.140 ms -3.3%
sum/compiled-from-Haskell/sum-left-data/100 245.3 μs 237.2 μs -3.3%
sum/compiled-from-Haskell/sum-left-data/500 1.367 ms 1.315 ms -3.8%
sum/compiled-from-Haskell/sum-left-data/1000 3.074 ms 2.978 ms -3.1%
sum/compiled-from-Haskell/sum-left-data/2500 8.360 ms 8.111 ms -3.0%
sum/compiled-from-Haskell/sum-left-data/5000 17.57 ms 17.05 ms -3.0%
sum/hand-written-PLC/sum-right-builtin/100 56.63 μs 54.30 μs -4.1%
sum/hand-written-PLC/sum-right-builtin/500 283.2 μs 275.1 μs -2.9%
sum/hand-written-PLC/sum-right-builtin/1000 591.3 μs 567.6 μs -4.0%
sum/hand-written-PLC/sum-right-builtin/2500 1.724 ms 1.665 ms -3.4%
sum/hand-written-PLC/sum-right-builtin/5000 3.748 ms 3.629 ms -3.2%
sum/hand-written-PLC/sum-right-Scott/100 36.48 μs 36.19 μs -0.8%
sum/hand-written-PLC/sum-right-Scott/500 198.6 μs 195.2 μs -1.7%
sum/hand-written-PLC/sum-right-Scott/1000 424.5 μs 419.9 μs -1.1%
sum/hand-written-PLC/sum-right-Scott/2500 1.584 ms 1.561 ms -1.5%
sum/hand-written-PLC/sum-right-Scott/5000 4.467 ms 4.411 ms -1.3%
sum/hand-written-PLC/sum-left-builtin/100 60.11 μs 57.16 μs -4.9%
sum/hand-written-PLC/sum-left-builtin/500 297.2 μs 284.3 μs -4.3%
sum/hand-written-PLC/sum-left-builtin/1000 591.2 μs 567.5 μs -4.0%
sum/hand-written-PLC/sum-left-builtin/2500 1.472 ms 1.413 ms -4.0%
sum/hand-written-PLC/sum-left-builtin/5000 2.926 ms 2.802 ms -4.2%
sum/hand-written-PLC/sum-left-Scott/100 41.10 μs 39.13 μs -4.8%
sum/hand-written-PLC/sum-left-Scott/500 220.7 μs 218.1 μs -1.2%
sum/hand-written-PLC/sum-left-Scott/1000 498.8 μs 489.1 μs -1.9%
sum/hand-written-PLC/sum-left-Scott/2500 1.821 ms 1.791 ms -1.6%
sum/hand-written-PLC/sum-left-Scott/5000 4.619 ms 4.564 ms -1.2%
837a156 5ac006c Change
TOTAL 283.0 ms 274.4 ms -3.0%

| FrameConstr !(CekValEnv uni fun ann) {-# UNPACK #-} !Word64 ![NTerm uni fun ann] !(ArgStack uni fun ann) !(Context uni fun ann)
-- ^ @(constr i V0 ... Vj-1 _ Nj ... Nn)@
| FrameCases !(CekValEnv uni fun ann) !(V.Vector (NTerm uni fun ann)) !(Context uni fun ann)
| FrameCases ann !(CekValEnv uni fun ann) !(V.Vector (NTerm uni fun ann)) !(Context uni fun ann) -- TODO: This is bad
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Interestingly, this doesn't hurt the performance. I still think this is bad tough

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Okay, #7189 will allow us to fix this by constructing term with arbitrary annotation.

, TyBuiltin @TyName ann $ SomeTypeIn $ DefaultUniList ty
])
]
_ -> Left $ "Casing on list requires two branches"
Copy link
Contributor

Choose a reason for hiding this comment

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

I discussed it with @zliu41 and IIRC we agreed that we should allow only one branch too for the cons case, since a lot of time it's expected that the list is gonna be non-empty and it would be wasteful to have a branch for the nil case when it's supposed to fail evaluation anyway.

@zliu41 we still need to reconcile it with False being the default for Bool. It's not too late to change things I think. Maybe we should make True and (:) the default branches for consistency. We can do it with or without reordering them. So let's discuss it some time.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I added single case as well

Copy link
Contributor

Choose a reason for hiding this comment

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

Change the error message too.

I suppose do it for booleans too while you're here? To make it consistent.

Copy link
Collaborator Author

@SeungheonOh SeungheonOh Jul 9, 2025

Choose a reason for hiding this comment

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

For Bool, do we want to enforce that number of branches can only be exactly one or two?

Current the type annotation allows some other "trailing" branches to be present--like case (con bool False) foo bar baz bob rob cob) where everything besides foo and bar will be ignored. However, current builtin casing itself doesn't allow it, so it would need to be fixed to match one behavior or another.

I don't see any use of this; bool casing with more than two branches would need to be statically removed anyways for script size optimization. We should only allow one or two branches on bool casing

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I'll go forward with only one or two branches allowed, but please let me know if there is a good argument against this.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, that's what I attempted to suggest. Thanks.

, TyBuiltin @TyName ann $ SomeTypeIn $ DefaultUniList ty
])
]
_ -> Left $ "Casing on list requires two branches"
Copy link
Contributor

Choose a reason for hiding this comment

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

Change the error message too.

I suppose do it for booleans too while you're here? To make it consistent.

headSpine :: Opaque val asToB -> [val] -> Opaque (HeadSpine val) b
headSpine (Opaque f) = Opaque . \case
headSpineOpaque :: Opaque val asToB -> [val] -> Opaque (MonoHeadSpine val) b
headSpineOpaque (Opaque f) = Opaque . \case
Copy link
Contributor

Choose a reason for hiding this comment

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

Reuse headSpine? Doesn't matter much, I'm gonna remove this anyway.

Copy link
Contributor

Choose a reason for hiding this comment

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

headSpineOpaque is no longer needed at all?

Copy link
Collaborator Author

@SeungheonOh SeungheonOh Jul 14, 2025

Choose a reason for hiding this comment

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

Yes, with the removal of CaseData and CaseList. I will remove

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I think it's okay to leave this actually. This can be useful future for adding other builtins

Right res -> computeCek ctx env res
Left err -> throwErrorDischarged (OperationalError $ CekCaseBuiltinError err) e
Right (HeadOnly fX) -> computeCek ctx env fX
Right (HeadSpine f xs) -> computeCek (transferConstantSpine xs ctx) env f
Copy link
Contributor

Choose a reason for hiding this comment

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

Using Either here was stupid on my part, should've introduced a dedicated strict data type.

But now that I look at it, it's probably best to inline HeadSpine business in such a data type, so that it has three constructors (error / success with only head / success with head and spine).

Not in this PR though, let's do it separately and measure whether it helps.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I'll make a PR for this after this one

@@ -1 +1 @@
forall a. Opaque Val (Integer -> [Data] -> TyVarRep * ('TyNameRep * "a" 0)) -> Opaque Val ([(Data,Data)] -> TyVarRep * ('TyNameRep * "a" 0)) -> Opaque Val ([Data] -> TyVarRep * ('TyNameRep * "a" 0)) -> Opaque Val (Integer -> TyVarRep * ('TyNameRep * "a" 0)) -> Opaque Val (ByteString -> TyVarRep * ('TyNameRep * "a" 0)) -> Data -> Opaque (HeadSpine Val) (TyVarRep * ('TyNameRep * "a" 0)) No newline at end of file
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This will go anyways, but need to appease CI

@SeungheonOh
Copy link
Collaborator Author

/benchmark lists

@github-actions
Copy link
Contributor

Click here to check the status of your benchmark.

@github-actions
Copy link
Contributor

Comparing benchmark results of 'lists' on '589516f72' (base) and '87639ad20' (PR)

Results table
Script 589516f 87639ad Change
sort/ghcSort/50 136.6 μs 136.5 μs -0.1%
sort/ghcSort/100 315.0 μs 315.2 μs +0.1%
sort/ghcSort/150 545.6 μs 540.8 μs -0.9%
sort/ghcSort/200 737.9 μs 730.7 μs -1.0%
sort/ghcSort/250 951.5 μs 949.9 μs -0.2%
sort/ghcSort/300 1.249 ms 1.248 ms -0.1%
sort/insertionSort/50 436.4 μs 436.6 μs +0.0%
sort/insertionSort/100 1.750 ms 1.754 ms +0.2%
sort/insertionSort/150 3.933 ms 3.987 ms +1.4%
sort/insertionSort/200 7.015 ms 7.076 ms +0.9%
sort/insertionSort/250 11.02 ms 11.26 ms +2.2%
sort/insertionSort/300 15.89 ms 16.21 ms +2.0%
sort/mergeSort/50 438.6 μs 430.2 μs -1.9%
sort/mergeSort/100 996.4 μs 988.8 μs -0.8%
sort/mergeSort/150 1.624 ms 1.609 ms -0.9%
sort/mergeSort/200 2.279 ms 2.246 ms -1.4%
sort/mergeSort/250 2.981 ms 2.942 ms -1.3%
sort/mergeSort/300 3.631 ms 3.576 ms -1.5%
sort/quickSort/50 1.044 ms 1.050 ms +0.6%
sort/quickSort/100 4.411 ms 4.429 ms +0.4%
sort/quickSort/150 9.927 ms 9.983 ms +0.6%
sort/quickSort/200 17.57 ms 17.62 ms +0.3%
sort/quickSort/250 27.64 ms 27.81 ms +0.6%
sort/quickSort/300 39.82 ms 40.33 ms +1.3%
sum/compiled-from-Haskell/sum-right-builtin/100 80.12 μs 44.81 μs -44.1%
sum/compiled-from-Haskell/sum-right-builtin/500 418.0 μs 235.5 μs -43.7%
sum/compiled-from-Haskell/sum-right-builtin/1000 898.6 μs 506.9 μs -43.6%
sum/compiled-from-Haskell/sum-right-builtin/2500 2.766 ms 1.670 ms -39.6%
sum/compiled-from-Haskell/sum-right-builtin/5000 5.991 ms 3.949 ms -34.1%
sum/compiled-from-Haskell/sum-right-Scott/100 43.81 μs 44.86 μs +2.4%
sum/compiled-from-Haskell/sum-right-Scott/500 231.9 μs 237.2 μs +2.3%
sum/compiled-from-Haskell/sum-right-Scott/1000 509.4 μs 516.9 μs +1.5%
sum/compiled-from-Haskell/sum-right-Scott/2500 1.805 ms 1.826 ms +1.2%
sum/compiled-from-Haskell/sum-right-Scott/5000 4.185 ms 4.223 ms +0.9%
sum/compiled-from-Haskell/sum-right-data/100 226.3 μs 186.0 μs -17.8%
sum/compiled-from-Haskell/sum-right-data/500 1.238 ms 1.014 ms -18.1%
sum/compiled-from-Haskell/sum-right-data/1000 2.824 ms 2.385 ms -15.5%
sum/compiled-from-Haskell/sum-right-data/2500 7.645 ms 6.703 ms -12.3%
sum/compiled-from-Haskell/sum-right-data/5000 16.21 ms 14.31 ms -11.7%
sum/compiled-from-Haskell/sum-left-builtin/100 79.27 μs 43.64 μs -44.9%
sum/compiled-from-Haskell/sum-left-builtin/500 407.8 μs 231.1 μs -43.3%
sum/compiled-from-Haskell/sum-left-builtin/1000 882.4 μs 498.0 μs -43.6%
sum/compiled-from-Haskell/sum-left-builtin/2500 2.708 ms 1.593 ms -41.2%
sum/compiled-from-Haskell/sum-left-builtin/5000 5.977 ms 3.830 ms -35.9%
sum/compiled-from-Haskell/sum-left-Scott/100 44.22 μs 43.20 μs -2.3%
sum/compiled-from-Haskell/sum-left-Scott/500 238.7 μs 231.4 μs -3.1%
sum/compiled-from-Haskell/sum-left-Scott/1000 520.6 μs 510.3 μs -2.0%
sum/compiled-from-Haskell/sum-left-Scott/2500 1.785 ms 1.759 ms -1.5%
sum/compiled-from-Haskell/sum-left-Scott/5000 4.215 ms 4.113 ms -2.4%
sum/compiled-from-Haskell/sum-left-data/100 234.5 μs 187.5 μs -20.0%
sum/compiled-from-Haskell/sum-left-data/500 1.295 ms 1.038 ms -19.8%
sum/compiled-from-Haskell/sum-left-data/1000 2.930 ms 2.425 ms -17.2%
sum/compiled-from-Haskell/sum-left-data/2500 7.983 ms 6.711 ms -15.9%
sum/compiled-from-Haskell/sum-left-data/5000 16.87 ms 14.57 ms -13.6%
sum/hand-written-PLC/sum-right-builtin/100 79.06 μs 77.86 μs -1.5%
sum/hand-written-PLC/sum-right-builtin/500 405.4 μs 400.1 μs -1.3%
sum/hand-written-PLC/sum-right-builtin/1000 844.3 μs 830.4 μs -1.6%
sum/hand-written-PLC/sum-right-builtin/2500 2.364 ms 2.343 ms -0.9%
sum/hand-written-PLC/sum-right-builtin/5000 4.968 ms 4.924 ms -0.9%
sum/hand-written-PLC/sum-right-Scott/100 35.16 μs 36.19 μs +2.9%
sum/hand-written-PLC/sum-right-Scott/500 190.7 μs 197.1 μs +3.4%
sum/hand-written-PLC/sum-right-Scott/1000 410.9 μs 425.6 μs +3.6%
sum/hand-written-PLC/sum-right-Scott/2500 1.537 ms 1.578 ms +2.7%
sum/hand-written-PLC/sum-right-Scott/5000 4.380 ms 4.447 ms +1.5%
sum/hand-written-PLC/sum-left-builtin/100 81.98 μs 81.89 μs -0.1%
sum/hand-written-PLC/sum-left-builtin/500 397.7 μs 391.1 μs -1.7%
sum/hand-written-PLC/sum-left-builtin/1000 788.2 μs 778.3 μs -1.3%
sum/hand-written-PLC/sum-left-builtin/2500 1.955 ms 1.930 ms -1.3%
sum/hand-written-PLC/sum-left-builtin/5000 3.889 ms 3.844 ms -1.2%
sum/hand-written-PLC/sum-left-Scott/100 40.26 μs 39.59 μs -1.7%
sum/hand-written-PLC/sum-left-Scott/500 214.8 μs 220.3 μs +2.6%
sum/hand-written-PLC/sum-left-Scott/1000 480.1 μs 491.1 μs +2.3%
sum/hand-written-PLC/sum-left-Scott/2500 1.774 ms 1.797 ms +1.3%
sum/hand-written-PLC/sum-left-Scott/5000 4.545 ms 4.569 ms +0.5%
589516f 87639ad Change
TOTAL 277.0 ms 262.7 ms -5.2%

@effectfully
Copy link
Contributor

Not bad!

@SeungheonOh
Copy link
Collaborator Author

sum/compiled-from-Haskell/sum-right-builtin improvements are nice! Almost 35% avg on that category

@effectfully
Copy link
Contributor

Make sure to check that the budget reductions are aligned with the performance improvements. We don't want to see, say, a 70% budget reduction when the code is only 40% faster.

@SeungheonOh
Copy link
Collaborator Author

SeungheonOh commented Jul 10, 2025

Do we currently have configurable budgeting mechanism for casing? I haven't seen any budget related code on CEK for casing.

@effectfully
Copy link
Contributor

Do we currently have configurable budgeting mechanism for casing? I haven't seen any budget related code on CEK for casing.

We don't, it's just the regular cost of a single CEK step.

(/\dead -> z)
(/\dead -> f (headList {a} xs) (tailList {a} xs))
{r})
\(z : r) (f : a -> list a -> r) (xs : list a) -> case r xs [z, f])
Copy link
Contributor

Choose a reason for hiding this comment

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

Hm, check how annAlwaysInline instead of annMayInline in PlutusTx.Compiler.Builtins affects things.

Copy link
Contributor

Choose a reason for hiding this comment

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

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yeah, can confirm, I checked too, no changes

Term Size: 1_391
Flat Size: 1_977
CPU: 186_924_676
Memory: 721_804
Copy link
Contributor

Choose a reason for hiding this comment

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

20% MEM reduction is pretty wild.

Comment on lines -1 to +4
CPU: 20_088_713
Memory: 72_250
Term Size: 89
Flat Size: 654
CPU: 8_111_579
Memory: 33_498
Term Size: 71
Flat Size: 641
Copy link
Contributor

Choose a reason for hiding this comment

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

Wow.

Comment on lines 1 to +4
CPU: 5_706_022
Memory: 10_678
Term Size: 165
Flat Size: 1_208
Term Size: 147
Flat Size: 1_194
Copy link
Contributor

Choose a reason for hiding this comment

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

Wait, how is is possible that CPU and MEM didn't change?

Copy link
Collaborator Author

@SeungheonOh SeungheonOh Jul 10, 2025

Choose a reason for hiding this comment

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

probably because the script never needed to match on list. This is before fully evaluating term so makes sense

Left _ -> False
Right EvaluationFailure -> length is /= 2 && (scrut || length is /= 1)
Left _ -> length is /= 1 && length is /= 2
Right EvaluationFailure -> scrut || length is == 2 -- scrut implies length = 2
Copy link
Contributor

Choose a reason for hiding this comment

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

Hm. So let's say there's a bug in the evaluator causing it to fail whenever scrut is True. Type checking succeeds, evaluation fails and you say it's ok? Or am I reading it wrong?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Type checker is checking is correct number of branches and correct type for branches. If type checking passes but evaluation fails then it means that's matching True with single branch.

Copy link
Collaborator Author

@SeungheonOh SeungheonOh Jul 10, 2025

Choose a reason for hiding this comment

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

oh wait, I think I messed up. It should be scrut && length is /= 2

Copy link
Contributor

Choose a reason for hiding this comment

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

If type checking passes but evaluation fails then it means that's matching True with single branch.

No it doesn't, because maybe I implemented casing on lists wrong and it just always throws on True or something.

force
(force (force chooseList)
(\s acc xs ->
case xs [acc, (\hd -> (\x -> s s x) (force mkCons hd acc))])))
Copy link
Contributor

Choose a reason for hiding this comment

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

Nevermind about inlining caseList, it seems to inline perfectly well in the end.

Comment on lines -1 to +4
CPU: 1_827_714
Memory: 7_992
Term Size: 81
Flat Size: 76
CPU: 752_100
Memory: 4_800
Term Size: 66
Flat Size: 66
Copy link
Contributor

Choose a reason for hiding this comment

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

Cool.

l
[ `$dMkNil`
, (\ds xs ->
force (force (drop (delay (\x -> x))))
Copy link
Contributor

Choose a reason for hiding this comment

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

"force force drop delay id" is a piece of modern art.

Comment on lines -1 to +4
CPU: 19_055_427
Memory: 84_856
Term Size: 119
Flat Size: 122
CPU: 4_736_100
Memory: 29_700
Term Size: 86
Flat Size: 96
Copy link
Contributor

Choose a reason for hiding this comment

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

Impressive.

@SeungheonOh
Copy link
Collaborator Author

Should be good to go now

@SeungheonOh
Copy link
Collaborator Author

SeungheonOh commented Jul 11, 2025

Performance improvement here is pretty sweat, but multi-let will improve it much more. Since multi-bind will remove the need for matching on list repeatedly which will be a massive improvement.

Alternatively, we can have annotated case matching which would be also very useful.

-- only matching branches get executed.
-- | Generate a term that does a lot of casing on boolean
casingBool :: Integer -> Term
casingBool 0 = constant () $ someValueOf DefaultUniInteger 42
Copy link
Contributor

Choose a reason for hiding this comment

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

Great benchmarks.

headSpine :: Opaque val asToB -> [val] -> Opaque (HeadSpine val) b
headSpine (Opaque f) = Opaque . \case
headSpineOpaque :: Opaque val asToB -> [val] -> Opaque (MonoHeadSpine val) b
headSpineOpaque (Opaque f) = Opaque . \case
Copy link
Contributor

Choose a reason for hiding this comment

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

headSpineOpaque is no longer needed at all?

listElem
(mkConstant () scrut)
[ mkConstant @Integer () 42
, lamAbs () x listElem $ lamAbs () xs list $ var () x
Copy link
Contributor

Choose a reason for hiding this comment

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

We should rename Bool success to Bool success 2 and add Bool success 1 for when there's only one branch. And do the same here. Because Bool any doesn't properly cover the case with a single branch and the False scrutinee.

But that can be a separate PR.

kase ()
listElem
(mkConstant () scrut)
[ lamAbs () x listElem $ lamAbs () xs list $ var () x
Copy link
Contributor

Choose a reason for hiding this comment

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

This doesn't cover the case when there's more branches than expected.

It's also out of sync with the Bool tests, which have very similar constraints. I do think it's a good idea to have the two that you have there, but then we should also

  1. add a test for when there's more branches than expected
  2. structure the Bool tests the same way

I felt like Bool any was an OK way to merge what you have here and the too-many-branches test into a single test, but I never actually measured coverage, so if you want to split it into two, that's even better I guess.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I tested coverage, and it was pretty okay. Regardlessly, I think it's better to have separate cases.

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants