-
Notifications
You must be signed in to change notification settings - Fork 479
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
Builtins #487
Comments
On static/dynamic builtins: IMO it would be nice if there were eventually only one class of builtin, i.e. our current "static" builtins were just turned into dynamic builtins. Dynamic ones seem strictly more powerful, so removing the weaker version in favour of that seems good. This also solves the naming issues since we only have one thing! (Although they're no longer "builtin", really...) For people following along: here's how I've been thinking about the "turn PLC terms into Haskell values" problem.
|
Nah, probably still requires
I was previously opposed to that, but now I think you're right. I've just written the following comment in
If we are going to use dynamic builtins extensively (which is the case, right?), then there is no point in having more corner cases. But if we're going to use dynamic builtin names only for some hacks, then it makes sense to distinguish between hacks and the blessed approach.
One alternative is to analyze the PLC AST directly, but it's a nightmare. The motivation for using evaluators is elaborated in
You once said this:
It can be indeed the case that extending the result of evaluation is something that we actually need rather than embedding the entire Haskell into Plutus Core. I'll play with that. |
Yeah product types and lists should be enough, but I just didn't want to write the contracts on the assumption that we would be able to do this - now that I know this feature is planned I'm not blocked on it, I can mimick it easily for testing purposes. |
Ok, I'll add them then.
Makes perfect sense, but note that even though the feature is planned, it's not clear whether it's possible to implement it in a sensible way. This all is a bit hand-wavy right now.
Great. |
Added support for throwing a PLC error from a builtin name in #642 (not merged yet). We need to do a few things (better before experimenting with parameterizing
|
Interesting! My only question is how we would type a PLC term with these in it? I guess providing a type-environment at typechecking type and a term-environment at runtime is actually very similar to what we do for the current dynamic builtins. |
Yes. Except right now we look up only dynamic builtin names and there is a finite amount of them, while with the new approach we can extend environments indefinitely. "Got a Haskell value that you can't embed into PLC? Put it into the current environment and reference it by its index". But this sounds like it may require a GC with reference counting or something. |
Plus everything is done with unconstrained indices, which is unpleasant. |
Yes. But it's very good for experimenting at least and maybe as a temporary intermediate solution. |
This comment's an offshoot from the now-closed "Do we have keywords?" issue: #463 The PLC parser currently has special treatment for builtin names, so they really are built in. This'll have to change once we have extensible builtins: we'll have to look up names in a table or something to make sure they really exist. Fortunately you now have to say We'll also have to change the spec, but let's cross that bridge when we come to it. |
We already have extensible builtins in this sense. Here is an excerpt from the classic pretty-printer: instance PrettyBy (PrettyConfigClassic configName) (Builtin a) where
prettyBy _ (BuiltinName _ n) = pretty n
prettyBy _ (DynBuiltinName _ n) = pretty n
...
instance (PrettyClassicBy configName (tyname a), PrettyClassicBy configName (name a)) =>
PrettyBy (PrettyConfigClassic configName) (Term tyname name a) where
prettyBy config = cata a where
a (BuiltinF _ bi) = parens' ("builtin" </> prettyBy config bi) I don't think we've ever tested how this interacts with the parser. For example in genBuiltin :: MonadGen m => m (Builtin ())
genBuiltin = BuiltinName () <$> genBuiltinName i.e. we basically never generate a
I'd start with "if it's marked as a If you wish, you can add some tests related to extensible builtins and add support for extensible builtlins to the parser. |
Right, we haven't added anything about extensible builtins to the parser or spec, they're basically only available if you're constructing an AST directly. |
Done in #751.
Doing that in #983. Now that we don't have sizes, everything is straightforward. |
We have several kinds of builtins:
Static builtin names like
addInteger
,takeByteString
,BlockNum
, etc. Right now each of them has its Haskell interpretation exceptintToByteString
,VerifySignature
,TxHash
andBlockNum
. This document provides some information on how we compute static builtins application in a well-typed way. In the implementation static builtin names are not saturated, while in the specification they are saturated, so this is something that needs to be fixed.Dynamic builtin names like
charToString
andtrace
. Those are functions that we can extend the language with, but that are not provided by default. Dynamic builtin names are handled analogously to static builtin names, it's just that for a static builtin name we know itsTypeScheme
(see the doc reference above) and interpretation statically, but for a dynamic builtin name we require the user (where "the user" = "someone who invokes the type checking procedure or one of the abstract machines") to provide them. This means that we only do some look-ups in maps storing types or interpretations of dynamic builtin names during type checking and evaluation, i.e. dynamic builtin names are not harder than static builtin names, just a little bit of boilerplate.Dynamic builtin types. There are two possible forms of them: a complicated one and a very complicated one. Right now the former is implemented, but we really want the latter. The complicated form is described in
Language.PlutusCore.Constant.Typed
in Note [Semantics of dynamic built-in types]. The most important part isYou might think this is a minor thing, however together with dynamic builtin names this gives us some great potential and a lot of complexity. For example, we already can convert Plutus Core values to Haskell values using some terrible hacks:
This all is elaborated in
Language.PlutusCore.Constant.Typed
.However, we of course want to remove this
unsafePerformIO
nonsense which means we need to be able to somehow put values of arbitrary Haskell types into the Plutus Core AST. Having this ability we can simply fold over a PLC data type inside PLC (using the CEK machine or any other evaluators that knows how to handle dynamic builtin names), but collect a Haskell value in an accumulator. And then the result of evaluation of a fold over a PLC data type is a very shallow wrapper around a Haskell value which we can then easily extract. And it should be possible to construct such fold in generic way, i.e. derive them from theGeneric
instance of a Haskell data type.Of course, embedding the entire Haskell into Plutus Core is not a trivial thing. I have some ideas, but I do not really know whether they make sense or not.
Meanwhile, @j-mueller, right now we can convert PLC lists to Haskell lists (and hence lists of lists, lists of lists of lists, etc). I think, I can add support for sum and product types (without
unsafePerformIO
nonsense). This does not allow to convert an arbitrary PLC to value to a Haskell value, but maybe it's enough to unblock you at least?Oh, and please someone suggest better names for these things.
The text was updated successfully, but these errors were encountered: