-
Notifications
You must be signed in to change notification settings - Fork 483
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Could untyped plutus core have primitives which don't need initial force #4183
Comments
These are somewhat artificial. Type abstractions in typed PLC block evaluation, so we erase abstractions to |
Checking some more, E.g. |
The primitives don't appear that much in the grand scheme of things. If we were concerned about this then the number of (Also term tags are actually only 4 bits, not a whole byte.) |
I run a quick test (rewrite
The counts are (node size, serialized size of term using DeBruijn names), that's 4% reduction in node count and 2% serialized size. I think that is significant in the grand scheme of things. |
Thanks, that's a useful datapoint! Let me elaborate a bit more on why this is tricky. Consider the following program (in pseudo-PIR):
The So at the very least it must be tolerable to force builtin functions. At the moment we require you to force exactly where you would otherwise pass a type. Perhaps we could not require you to do any forcing. The only problematic case would be a nullary builtin which had only type arguments and immediately failed (e.g. I have a feeling we've been through this discussion before, @kwxm do you remember anything else? |
I don't agree, it is not tricky: You can do rewrite in two steps:
Let me write Your example would be rewritten as: usesTrace (builtin trace) 0 -> -- replace with delayed versions
usesTrace (delay (builtin! trace)) 0 -- note: builtin! And indeed, in the compiled PLC there is
That grows in size, but that doesn't actually happen. GHC rarely passes If we rewrite the example as (which is closer to what inferred types would be): errorExample2 :: Integer
errorExample2 =
let usesTrace :: (BuiltinString -> Integer -> Integer) -> Integer -> Integer
usesTrace tracer i = tracer "I saw it" i
evilTrace :: forall a . BuiltinString -> a -> a
evilTrace s v = traceError "I'm evil"
i1 = usesTrace trace 0
i2 = usesTrace evilTrace 1
in i1 + i2 The line above becomes
which would simplify:
The polymorphic program has size 54, simple one 53, and latter could become smaller. EDIT: What does |
Yes, you're certainly right about that, but even if it's a corner case we thought it was important for builtins to behave exactly the same as polymorphic functions. That way you don't have to worry about the corner cases.
Nice idea. This assumes that all the type arguments come first, but at the moment our builtins can have interleaved term and type arguments. This is pretty pointless however, and we might as well require the type arguments to come first. If we did that and banned nullary builtins, I think this could work.
It's stuck. |
I think that removing the head type-arguments is already an improvement. If it's possible to shuffle the type arguments to the front, that would be even better, but do you have such builtins? (The specification doesn't list their types, nor haddocks, list their types, that would be helpful). |
It looks like that types of builtins are generated by I think GHC pushes all foralls to the front in inferred types. That trick is cool but feels dangerous, I'd prefer having types of builtins checked (against explicitly written ones) rather than inferred from their Haskell-meaning. EDIT: if (U)PLC is a compilation target the types or "call convention" (in case of UPLC) is an important information to have in the spec. |
This is unfortunate. I liked the "builtins have to fully saturated" design more (when there isn't such problem). It's easier to show that semantics are preserved then. (My proposal would been completely trivial then). |
We had a long argument about saturated vs unsaturated builtins. In the end we opted for unsaturated - perhaps a mistake, but here we are. |
We've been able to gather some interest on this specific topic and Oleg's proposal. @michaelpj @phadej Should we add it to #4174 and attempt it in the upcoming weeks? |
This is an intrusive proposal as it changes the UPLC. Everything listed in #4174 doesn't seem to require changes, even in typed PLC, as they can happen on PIR-level, which makes them a lot more realistic to get done :) I opened this issue "early" because I expect it take long to fix, if it will ever. |
I know, but it is well-scoped and elegant. We also suspect the improvements would be non-trivial, and our transpilers would take fewer |
Yes, this would be a change to the semantics of the language, and might well require a new language version and changes to the spec (which we're in the process of redoing already). It's a much more complicated change, and I don't think it will be that significant in the grand scheme of things. It's something we can hopefully roll in easily enough when we do do another version. |
Okay, I'll just add this to #4174 for tracking for now. |
We don't.
See the golden files. Generating a haddock comment using
Within
We don't rely on GHC pushing the
|
Sorry, I just noticed this after it was quoted in a previous comment. The
That still doesn't quite tell the full story because sometimes |
@kwxm that's great. |
There's now a CIP for this discussion, hence I'm closing the ticket. Feel free to reopen if you disagree. |
by looking at some contracts' plutus core, there are some of
(force mkCons)
,(force trace)
,(force ifThenElse)
for example. I guess in these forcings are cheap to store and execute, but they aren't entirely free.EDIT: I think I haven't seen these combinators used unforced.
The text was updated successfully, but these errors were encountered: