Touch Grass
Common effect definitions for your Eat Your Greens (EYG) runtime.
Every interaction between an EYG program and the outside world is managed via an effect. This includes filesystems, network sockets, clocks, randomness, environment variables and anything else.
Note, this library defines only interfaces, the types and encode/decode functions, not a concrete implementation. Your runtime will need to do that.
Usage
gleam add touch_grass
This example creates an EYG runner that allows programs to talk to the outside world via the Fetch effect.
import eyg/interpreter/break
import eyg/interpreter/expression as r
import eyg/interpreter/value
import gleam/fetch
import gleam/string
/// Accept the source as an EYG IR tree
pub fn run(source) {
let scope = []
loop(r.execute(source, scope))
}
/// Handle the raised effect if it is a fetch effect and resume.
/// Treat all other break reasons as an error.
fn loop(return) {
case return {
Ok(value) -> promise.resolve(Ok(value))
Error(#(reason, _meta, env, k)) ->
case reason {
break.UnhandledEffect("Fetch", lift) ->
case fetch.decode(lift) {
Ok(request) ->
loop(r.resume(fetch.encode(do_fetch(request)), env, k))
Error(reason) -> promise.resolve(Error(reason))
}
_ -> promise.resolve(Error(reason))
}
}
}
fn do_fetch(request) {
send_bits(request)
|> result.map_error(string.inspect)
}
fn send_bits(request) {
use response <- promise.try_await(fetch.send_bits(request))
fetch.read_bytes_body(response)
}
Design principles
- Sync effects: Concurrency and async execution are concerns of the runtime, not the interface contract.
- Errors are values: Every fallible operation returns a
Result, EYG has no support for panics or exceptions. - Independent effects A runtime can compose any subset of the effects defined in this library.
The touch_grass library is influenced by patterns like Hardware Abstraction Layer (HAL) and ports and adapters.