DEV Community

Cover image for Playing around with Elvish, a new(ish) shell
Daniel Fitzpatrick
Daniel Fitzpatrick

Posted on

Playing around with Elvish, a new(ish) shell

1

Discovering Elvish

Last year the youtube algorithm suggested I watch this video, a brief explanation of the vision behind a new shell. The video itself was a few years old, so I was pleased to discover a busy Github repo and active community. I installed elvish and went about my business, pridefully thinking that my familiarity with bash would act as a stalwart defense against any noob mistakes. A couple of noob mistakes made in quick succession convinced me I had better read the docs anyway.

This wasn't as bad as expected. The Elvish docs were expertly organized and easy to read. For maybe the first time ever I felt inspired to write a decent amount of code in a shell scripting language.

Elvish offers first-class support for a number of features that are interesting to find in a shell scripting language, but they are seamlessly integrated and never feel out of place.

  • lexical scopes
  • types/kinds
  • sensible math operators
  • proper function signature with var-args
  • plus optional named params with default values
  • higher-level functions
  • persistent, immutable lists & maps
  • parallel execution
  • namespaces
  • package manager!!!
  • so much more...

One feature I have not yet taken advantage of in my own projects are the styling builtins. I am eager to see how they simplify some extant parts of my project.

Goofing around

The first thing I did was to implement some of the core library functions from Clojure. 2

fn partial [f @supplied]{
  put [@args]{ 
    @args = (base:check-pipe $args)
    $f $@supplied $@args 
  }
}

fn juxt [@fns]{
  put [@args]{
    @args = (base:check-pipe $args)
    for f $fns {
      $f $@args
    }
  }
}

fn reduce [f acc @arr]{
  for a $arr {
    acc = ($f $acc $a)
  }
  put $acc
}

This gives you currying, juxtaposition, and (ofc) folding.

# all of this available in the 'fun' and 'base' namespaces
# except in the float64 type signature, '()' is output capture in elvish eg '$()' or '``'
# $<fn>~ is a function handle/reference

~> (fun:juxt $base:dec~ $base:inc~) 10
(float64 9)
(float64 11)

~> (fun:partial $+~ 2) 10
(float64 12)

~> fun:reduce $+~ (range 10)
(float64 45)

In the next entry I may write about my approach to lazy iterators(!!) in Elvish, or how seamless the Elvish package manager has made the development process.


  1. Cover image made by Matty Rodgers - unfinished piece entered in a competition. 

  2. I eventually wrote a great deal of them here

Top comments (0)