RETURNDATASIZEopcode is the way to do it
@siraben: I haven't tried to implement a lazy functional language before, but I think I understand the basic ideas.
I like the idea of your runtime being a graph of combinators, since any formalisation of the high-level language maps closely to the combinator representation. So if you prove that your translation of the combinators to EVM instructions is correct, then you have a kind of two-step proving strategy for executing verified code.
@siraben What is your language's current goals, besides lazy evaluation as a proof-of-concept?
How something like an ERC-20 token works in declarative syntax: Easily. When you think about it, "Create your own ERC-20 token" websites give the recipe as a static 4-tuple of (Name, Symbol, Decimal Places, Total Tokens). So this is the simplest mainstream declarative recipe for an ERC-20 token. So we add more rules on top to resemble classical financial derivatives, like time/oracle/conditional primitives.
How Lira does it is that you hoist out contract calls, so rather than a syntax tree that contain transfers, you turn that into a list of transfers and some chunk of logic that determines if those transfers are to be made. In Lira's example, the logic that evaluates "if-within" for oracles depends on persistent storage memory so that an oracle that was once true during a condition's time-interval isn't checked again.
What I mean by execution semantics is that right now, a Lira contract can be deployed with all counterparties known beforehand, or counterparties can be added after contract deployment (but before contract execution initiates). This last run-mode was added later. But each contract deployment represents one instance of the contract being executed with one set of counterparties and one set of potential transfers.
So for CPU you care about strict/non-strict evaluation because it addresses resource concerns and expressibility.
For declarative blockchain languages it could mean the same, but it could also mean "how do we actually execute this contract wrt. all the bits that the language is being implicit about?" -- for example, there is no explicit address book feature in Lira, and the implicit quantifiers for the counterparties are assumed to be "for exactly one party A, B and C:" But if it were a "for all parties A, B and C:" then the contract could be kind of like a factory (as in the OOP pattern) as I said.
Another thing about execution semantics: You might want to check some parts of a conditional first because it's cheaper rather than because it's listed first. (Even && in Haskell evaluates from left to right, but there are languages where even the order of execution of individual lines of code is non-deterministic because they're independent.) You might fold/optimize certain expressions at compile-time, or you might not.
You might even have an implicit cash-out retention policy as part of your execution semantics; after all, a part of execution cost suddenly involves interest rates. :D
@siraben Cool. :) So your angle is still purely language-expressivity rather than solve some particular business problem?
I suppose you can see any Solidity contract as a financial derivative, but before this comparison is truly impressive is when you can only exactly express things that people would normally do in financial derivatives and not a bunch of wrong stuff. Like, if you took someone who worked in the legal dept. of an exchange and showed him contract code and he/she'd say "yeah, that's this-and-that derivative."
I guess there were historical paper contracts where you use the actual piece of contract paper for keeping score of execution progress (stateful contract), but typically you will just want to say what kind of book-keeping you expect to happen, and the executors of the contract will manage it sensibly. This reminds me of the tally sticks that resulted in the burning of British parliament: https://en.wikipedia.org/wiki/Burning_of_Parliament