Skip navigation

What’s In A Shell

A reasonable shell is a domain specific language for talking about files. There are a few things to do with files:

  • read files
  • write files
  • run files

The reason a ‘Haskell shell’ or ‘Scheme shell’ or ‘Ruby shell’ is doomed to failure is because of the way ‘first class files’ need to be supported. It is not okay to `run` a command or read a file. No, these operations must be the first thing.

It is possible, by way of the method_missing function in Ruby, to make IRB behave like a shell when it searches for command definitions. If it can’t find the global method ls, then it calls method_missing. Define method_missing to search for invoke /usr/bin/env and you’re done (for POSIXish systems). However, that’s really not good enough, because variables should also be dug up out of the path; and never mind the vagaries of pipe syntax and all that kind of stuff. Admittedly, pipes and redirection can be represented differently, but they should be short.

How would you take a language you like — Haskell, Scheme, Python — and make it into a shell? You have to replumb the method for evaluating tokens. Any undefined token could be a file name. The type for that filename depends on it’s place in the expression tree. Many commands have complicated types. How do we unify cat‘s types?

  cat :: FileName -> String     -- reading from a file
  cat :: String -> String       -- reading from stdin, a heredoc

Never mind the question of how we assign a type to cat in the first place. Defining a function cat is cheating — the whole point of a shell is that it let’s you use executable files in a first-class way, just like builtin commands.

In a few lifetimes, I’ll have a better appreciation of what makes a shell a shell. It’s worth considering that job control — an invisible feature of many shells — could be made explicit to good effect.


Post a Comment

You must be logged in to post a comment.
%d bloggers like this: