-
Notifications
You must be signed in to change notification settings - Fork 13
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
[#102] Use morley capabilities to define custom ADT layout #112
Conversation
) | ||
|
||
-- | Parse the stablecoin contract. | ||
parseStablecoinContract :: MonadThrow m => m (T.Contract (ToT Parameter) (ToT Storage)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we have that splice above, we know in compile time that the contract is valid (otherwise compilation fails). Can we use this knowledge here to avoid MonadThrow
and change it to just T.Contract (ToT Parameter) (ToT Storage)
? I am bad at TH, but I suspect it should be straightforward.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we can, or at least not in that way.
The TH splice would have to compile the contract (already done), and then somehow emit a valid haskell expression of type T.Contract (ToT Parameter) (ToT Storage)
, as if it had been handwritten (not easily done).
In other words, what would the code generated by TH look like?
stablecoinContract :: T.Contract (ToT Parameter) (ToT Storage)
stablecoinContract = ???
Theoretically, the TH splice could pattern match on the parsed T.Contract (ToT Parameter) (ToT Storage)
, and build an Exp
AST representing calls to Michelson.Typed.Instr
and Michelson.Typed.Value
. It is doable, but it's a lot of work for little gain.
However, because the TH splice proves the contract is well-typed, we can change either throwM
to either error
, and get rid of MonadThrow
, and be sure that error
will never be called. Yeah, it makes the eyes bleed, but it's "safe" :P
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay
However, because the TH splice proves the contract is well-typed, we can change
either throwM
toeither error
, and get rid of MonadThrow, and be sure that error will never be called.
I think it's a good idea (as long as there is a comment explaining why the error can't happen here). It matches the idea of using error
for errors that can happen only in case of a programmer mistake.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done, looks a lot better now!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🆒
700c145
to
d58a80d
Compare
ac981dc
to
a287365
Compare
Problem: The Michelson representation (that is, the balancing of `pair` and `or`s) of our Haskell data types must match the Michelson representation of our Ligo data types. In the past, we used Haskell nested tuples in order to have complete control of the layout, but this leads to messy, hard to maintain code. Solution: Now that morley introduced `customGeneric` to control an ADT's layout, we can replace our nested tuples with Haskell ADTs and still have control of its layout.
Problem: The Michelson representation (that is, the balancing of `pair` and `or`s) of our Haskell data types must match the Michelson representation of our Ligo data types. In the past, we used Haskell nested tuples in order to have complete control of the layout, but this leads to messy, hard to maintain code. Solution: Now that morley introduced `customGeneric` to control an ADT's layout, we can replace our nested tuples with Haskell ADTs and still have control of its layout.
Problem: The Michelson representation (that is, the balancing of `pair` and `or`s) of our Haskell data types must match the Michelson representation of our Ligo data types. In the past, we used Haskell nested tuples in order to have complete control of the layout, but this leads to messy, hard to maintain code. Solution: Now that morley introduced `customGeneric` to control an ADT's layout, we can replace our nested tuples with Haskell ADTs and still have control of its layout.
Problem: The Michelson representation (that is, the balancing of `pair` and `or`s) of our Haskell data types must match the Michelson representation of our Ligo data types. In the past, we used Haskell nested tuples in order to have complete control of the layout, but this leads to messy, hard to maintain code. Solution: Now that morley introduced `customGeneric` to control an ADT's layout, we can replace our nested tuples with Haskell ADTs and still have control of its layout.
Problem: The Michelson representation (that is, the balancing of `pair` and `or`s) of our Haskell data types must match the Michelson representation of our Ligo data types. In the past, we used Haskell nested tuples in order to have complete control of the layout, but this leads to messy, hard to maintain code. Solution: Now that morley introduced `customGeneric` to control an ADT's layout, we can replace our nested tuples with Haskell ADTs and still have control of its layout.
Problem: The Michelson representation (that is, the balancing of `pair` and `or`s) of our Haskell data types must match the Michelson representation of our Ligo data types. In the past, we used Haskell nested tuples in order to have complete control of the layout, but this leads to messy, hard to maintain code. Solution: Now that morley introduced `customGeneric` to control an ADT's layout, we can replace our nested tuples with Haskell ADTs and still have control of its layout.
Problem: The Michelson representation (that is, the balancing of `pair` and `or`s) of our Haskell data types must match the Michelson representation of our Ligo data types. In the past, we used Haskell nested tuples in order to have complete control of the layout, but this leads to messy, hard to maintain code. Solution: Now that morley introduced `customGeneric` to control an ADT's layout, we can replace our nested tuples with Haskell ADTs and still have control of its layout.
Problem: The Michelson representation (that is, the balancing of `pair` and `or`s) of our Haskell data types must match the Michelson representation of our Ligo data types. In the past, we used Haskell nested tuples in order to have complete control of the layout, but this leads to messy, hard to maintain code. Solution: Now that morley introduced `customGeneric` to control an ADT's layout, we can replace our nested tuples with Haskell ADTs and still have control of its layout.
Problem: The Michelson representation (that is, the balancing of `pair` and `or`s) of our Haskell data types must match the Michelson representation of our Ligo data types. In the past, we used Haskell nested tuples in order to have complete control of the layout, but this leads to messy, hard to maintain code. Solution: Now that morley introduced `customGeneric` to control an ADT's layout, we can replace our nested tuples with Haskell ADTs and still have control of its layout.
Problem: The Michelson representation (that is, the balancing of `pair` and `or`s) of our Haskell data types must match the Michelson representation of our Ligo data types. In the past, we used Haskell nested tuples in order to have complete control of the layout, but this leads to messy, hard to maintain code. Solution: Now that morley introduced `customGeneric` to control an ADT's layout, we can replace our nested tuples with Haskell ADTs and still have control of its layout.
Problem: The Michelson representation (that is, the balancing of `pair` and `or`s) of our Haskell data types must match the Michelson representation of our Ligo data types. In the past, we used Haskell nested tuples in order to have complete control of the layout, but this leads to messy, hard to maintain code. Solution: Now that morley introduced `customGeneric` to control an ADT's layout, we can replace our nested tuples with Haskell ADTs and still have control of its layout.
Problem: The Michelson representation (that is, the balancing of `pair` and `or`s) of our Haskell data types must match the Michelson representation of our Ligo data types. In the past, we used Haskell nested tuples in order to have complete control of the layout, but this leads to messy, hard to maintain code. Solution: Now that morley introduced `customGeneric` to control an ADT's layout, we can replace our nested tuples with Haskell ADTs and still have control of its layout.
Problem: The Michelson representation (that is, the balancing of `pair` and `or`s) of our Haskell data types must match the Michelson representation of our Ligo data types. In the past, we used Haskell nested tuples in order to have complete control of the layout, but this leads to messy, hard to maintain code. Solution: Now that morley introduced `customGeneric` to control an ADT's layout, we can replace our nested tuples with Haskell ADTs and still have control of its layout.
Problem: We have two data types, `Storage` and `StorageView`, that are exactly the same, except `StorageView` has BigMapIds instead of BigMaps. As a consequence, we have to use `customGeneric` and declare the storage's layout twice, and these must be kept in sync at all times. This is a maintenance burden. Solution: Merge these two data types into `Storage' big_map`, declare the storage's layout once, and then define two type aliases for ease of use.
Problem: The Michelson representation of Haskell's `Parameter` and `Storage` must be an exact match of the Michelson repr of Ligo's corresponding data types. They must always be kept in sync, which is a maintenance burden. Solution: to make this a little bit easier to maintain, we can ✨sprinkle✨ some TH and check at compile-time that the Michelson reprs match. Also moved `parseStablecoinContract` and `parseRegistryContract` from `Stablecoin.Client.Contract` to `Lorentz.Contracts.Stablecoin`, because these functions are not really related to the stablecoin-client, they have other uses.
Problem: Now that we're using TH to check at compile-time that the contract can be parsed and typechecked, we should no longer need the MonadThrow constraint on parseStablecoinContract and parseRegistryContract. Solution: Inside a TH splice, after proving that the contract can be parsed+typechecked, we emit a haskell expression that reads the contract again at runtime, except it's now safe to use `error` instead of `throwM` because we know this can't possibly fail at runtime.
a287365
to
63140ef
Compare
Problem: In #112, we started parsing the stablecoin and metadata registry contracts at compile-time. We should do the same for the new stablecoin FA1.2 contract too. Solution: Parse the stablecoin FA1.2 contract at compile-time.
Problem: In #112, we started parsing the stablecoin and metadata registry contracts at compile-time. We should do the same for the new stablecoin FA1.2 contract too. Solution: Parse the stablecoin FA1.2 contract at compile-time.
Description
Problem: The Michelson representation (that is, the balancing of
pair
and
or
s) of our Haskell data types must match the Michelsonrepresentation of our Ligo data types.
In the past, we used Haskell nested tuples in order to have complete
control of the layout, but this leads to messy, hard to maintain code.
Solution: Now that morley introduced
customGeneric
to control an ADT'slayout, we can replace our nested tuples with Haskell ADTs and still
have control of its layout.
Related issue(s)
Resolves #102
✅ Checklist for your Pull Request
Related changes (conditional)
Tests
silently reappearing again.
Documentation
not essential.
Stylistic guide (mandatory)