Skip to content

Proposal: Extend ~ and ~~ to support code fragments? #212

@jpco

Description

@jpco

In es today, thunks are, to quote the man page, treated as "indivisible unit[s]". This is usually not a problem, but sometimes you want to crack a thunk open to see the list inside. Similarly, sometimes you want to test if some list (element) is a thunk, or in particular an empty thunk; to do this is clunky, sketchy, and requires a lot of obnoxious, noisy things like ~ $cmd ('{'*'}' '%closure'*'{'*'}').

It seems possible to extend the ~ and ~~ operators to improve these cases. What I'm imagining is something to the following effect: in

~ $cmd {*}

the pattern {*} would be interpreted as "is a thunk". In addition, it would intentionally ignore any lexical bindings, such that something like

let (a = b) ~ $cmd {*}

doesn't change the output produced given the same $cmd input.

One special case would be

~ $cmd {}

which would be interpreted as "an empty thunk", a thunk containing an empty list but otherwise equivalent to the case above.

Similarly, ~~ could be modified to extract the list contained by a thunk -- something like

; let (a = {foo bar baz}) echo <={~~ $a {*}}
foo bar baz

There would be a lot of questions to answer before something like this could be merged, like how to handle lambda expressions, the semantics of patterns like {foo*} or foo{*}, and how to gracefully "fall back" between thunk-ish {*} patterns and not-so-thunk-ish *}* patterns.

We'd need to define some kind of glomming semantics, too. For example, what would the following print?

local (a = b)
let (thunk = {$a $x})
let (x = z)
let (l = <={~~ $thunk {*}})
echo $thunk

There's also a problem with trying to extract "non-list" commands contained in a thunk; what would you get from {let (a = b) c}, or {x = y}, or even {~ a b}?

There are backwards-compatibility concerns, of course, though I'm not sure how many scripts are out there using {*} given how strange and unpredictable the actual behavior of ~ $x {*} is today. I know for my part I end up using the ugly quoted-up versions which would stay unchanged with this proposal.

We might also consider how this would interact with potential long-term changes like first-class environments, but that's far enough from the current state of things that it's hard to reason about.

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions