Yes, so basically everything runs in a monad conceptually similar to
Eff. The pure values are just those with an empty set of effects.
Things that you’d expect to work just work:
Things get more interesting though. For starters – the effectful values are treated the same way as any other value, which means they are lazy. The way to force effects is to use them “in their own line” – so that’s a bit like do notation. That means, unlike in most (impure) languages, the arguments are not forced when calling a function – it depends on the implementation of the function. Let me give you a few examples of that.
First, consider this function:
def const a b: a
b argument is never used, it is never evaluated when calling the function.
const (print "a") (print "b") will print
"a", but never
On the other hand:
def const' a b:
evalutes the argument (but drops the value). That means
const' (print "a") (print "b") actually prints
With this design things like:
print ("The user says: " + System.stdin.getLine)
Also work the way someone unfamiliar with Haskell (or other pure langs) would expect them to work.
This has some interesting consequences – consider the function
every from our standard library – it takes a time interval and a value, and repeatedly evaluates the value in given time intervals.
If you write:
val = getSomeNumberOverHTTP
every 5.seconds val
it will produce an infinite stream of the same number, available for consumption every 5.seconds.
On the other hand
every 5.seconds getSomeNumberOverHTTP
actually makes the network call every 5 seconds and returns a new value every time.
This gives a lot of flexibility when passing effectful computations around, while at the same time does not require you to think about things like “should I just apply the function,
fmap it, or maybe bind monadically?”.
This of course also requires some care when handling effectful values, but things get much easier when working with nodes – since every node corresponds to a line of code, the return values of nodes do not carry the side effects anymore (these got evaluated when computing the value), which is the behavior you’d expect most of the time.
If any part of the whole system is unclear, please do ask questions! This is one of the most interesting and probably “unfamiliar” design parts of Luna, so it’s very important to us for you to get the right ideas