It seems like the DAML REPL needs to connect to a ledger. Is there any way to use it with just pure functions for when you want to test out some functionality but not necessarily record a transaction on a ledger?
At the moment you always need a ledger connection but we might relax that in the future. However, if you do have a ledger connection you can easily test a pure function, e.g.,
debug (1 + 1)
will run the computation and print 2
(prefixed by some trace output).
What would be the easiest way to spin up the DAML REPL against a test ledger then?
Start sandbox via daml sandbox
(you don’t need a DAR or anything else) and then connect via daml repl --ledger-host localhost --ledger-port 6865
. You need the latest snapshot (1.4.0-snapshot.20200715.4733.0.d6e58626
or later) for this. Otherwise you also need to pass in a DAR.
Wouldn’t return (1 + 1)
with an --output-file
option be the more orthodox way of getting your hands on the value?
daml repl
and daml script
have mostly orthogonal usescases:
daml script
requires you to first build a DAR so the initial effort is fairly high. But once you have done that it’s easy to run the same script multiple times (e.g. everytime you initialize your ledger) and you can do so without a human watching it. --output-file
ties in well with that since it gives you machine-readable output.
daml repl
on the other hand is targeted at an interactive usecase. So it’s great for one-off usecases for interacting with the ledger or to explore how a function behaves for different inputs. You often don’t know what exactly you want to do here upfront so having to create a DAML projects, build a DAR and run it with daml script
is a pretty clunky replacement for this.
So if your goal is just to get the output of 1 + 1
and you never want to change that, daml script --output-file
might do the trick but it is by no means a replacement for exploring pure functions in daml repl
.
It would actually be really nice if you could run pure functions in the REPL without wrapping them in debug
for the learning experience in the katacoda’s I’m writing right now.
This would also bring the DAML REPL in line with how other REPLs behave.
I’ve actually just had a pretty long chat with @cocreature on that topic. My current thinking is I would not want the REPL to behave like the Haskell one, i.e. automatically print out pure expressions and execute effects. Given that effects in this case are recorded on a permanent, remote ledger, I’d be uncomfortable with providing an environment that is not either explicitly safe or explicitly unsafe.
Which I believe leaves us with two options:
- The REPL keeps not running pure expressions as it does now, but maybe we improve the error message to say something like “The DAML REPL can only execute Script expressions. If you want to run a pure value, wrap your expression in pure/return”. If we go down that route we should also imo always print out the result, such that:
daml> 1 + 1
<error msg>
If you want to run a pure expression, wrap it in return, e.g.:
return $ 1 + 1
daml> return $ 1 + 1
=> 2
daml> debug $ 1 + 1
2
=> ()
daml>
- The REPL assumes expressions are “pure” by default, and if the user wants to execute something, they have to explicitly wrap the expression in some other construct. Maybe
script
? The issue with this approach is it sort of requires introducing a special keyword just for the REPL, which only means something from the top-level of the REPL, which leads to a lot of special-casing and could end up murkying the code quite a bit. Also we don’t really have a great way to print out Script- or Action-typed values if we don’t execute them.
Opened Make it easier to run pure functions in DAML REPL · Issue #6780 · digital-asset/daml · GitHub to track this.
As for @Gary_Verhaegen’s point, I’m interested what others think here. I’ve used the Haskell REPL so much that the behavior there is how I expect all REPL to behave but that might not apply if you aren’t as familiar with it.
Given that we are only talking about allowing more pure operations, I don’t think this is particularly risky (switching the other way around and executing ledger operations in more places would be risky).
Having a special keyword that needs to go in front of any action to be executed is my least liked option. Other than that, I probably have a slight preference for making it behave like the Haskell REPL over having to wrap things in pure
. When I see error messages like If you want to run a pure expression, wrap it in return, e.g.:
, I just think: “If you know what I’m trying to do it, why don’t you just do it for me?!”
But I think either way we should print the result of every statement by default. If people want to swallow it, they can just use void
.
Perhaps a flag that switches between these two behaviors?
daml repl
- works like every other repl
daml repl --ledger-mode
- works how it currently is