Shell scripting is kinda broken:
- Shell scripting languages differ or are interpreted with subtle differences
- Higher level language concepts are typically missing
Can Haskell be a good replacement for Bash鈥攐r similar languages鈥攁s a shell scripting language?
-
Install Haskell Stack
brew install haskell-stack
-
Install turtle using Stack
stack install turtle
-
Define functions to setup/init/extend Haskell shell and create an alias hsh
hsh_setup() { local hsh_home="${HOME}/.hsh" mkdir -p ${hsh_home} printf "[INFO] Creating hsh config" printf ':set -XOverloadedStrings\n:set prompt "位> "\n:set +m\nimport Turtle\nimport Prelude hiding (FilePath)' > ${hsh_home}/.ghci printf "\n[INFO] hsh setup done" } hsh_extend() { local hsh_home="${HOME}/.hsh" \ command=${1} printf "\n[INFO] Creating function for command %-25s" "${command}" printf "\n%1\$s = \\\cl -> shell (\"%1\$s \" <> cl) empty\n%1\$s' = \\\cl -> shell (\"%1\$s \" <> cl)" ${command} >> ${hsh_home}/.ghci } hsh_init() ( local hsh_home="${HOME}/.hsh" hsh_setup while getopts "e:" option; do case ${option} in e) hsh_extend ${OPTARG} esac done cd ${hsh_home} stack ghci ) alias hsh=hsh_init
-
Run Haskell Shell and have fun 馃檶
$ hsh -e git -e latexmk -e typora [INFO] Creating hsh config [INFO] hsh setup done [INFO] Creating function for command git [INFO] Creating function for command latexmk [INFO] Creating function for command typora Note: No local targets specified, so a plain ghci will be started with no package hiding or package options. You are using snapshot: lts-17.2 If you want to use package hiding and options, then you can try one of the following: * If you want to start a different project configuration than /Users/main/.stack/global-project/stack.yaml, then you can use stack init to create a new stack.yaml for the packages in the current directory. * If you want to use the project configuration at /Users/main/.stack/global-project/stack.yaml, then you can add to its 'packages' field. Configuring GHCi with the following packages: GHCi, version 8.10.3: https://www.haskell.org/ghc/ :? for help Loaded GHCi configuration from /Users/main/.hsh/.ghci Loaded GHCi configuration from /private/var/folders/yz/b655kl71057db1lhwxhc0rt00000gs/T/haskell-stack-ghci/2a3bbd58/ghci-script
In the ghci REPL we can now use the Turtle library to do system programming similar to what we awould do in Bash. 馃殌
There are a couple cool aspects of Haskell/GHCI that are being used to provide a proper shell feeling:
-
monads: most Turtle functions like
dir
andecho
are monadic位> :t pwd pwd :: MonadIO io => io FilePath
and GHCI executes code within an IO monad; that means we can write in do-notation style and read/write from/to input/output
位> dir <- pwd
-
overloaded strings:
E.g.
echo
has typeecho :: MonadIO io => Line -> io ()
(i.e. expectsLine
notString
) which can however use the overloaded string literal syntax位> echo "Hi!"
-
printing of return values: types like
FilePath
are printable and GHCI prints every value that is entered so we can immediately see results of commands位> dir <- pwd 位> dir FilePath "/Users/friedrichk/.hsh"
The Turtle tutorial on Hackage has more examples. Be sure to check it out.
- No Tab-Completion for commands/paths
- No Syntax-Highlighting
In a terminal emulator like iTerm, we can start hsh in every new window/tab in order to get a complete Haskell based Terminal feeling.
ptghci adds useful features like syntax highlighting and tab completion and might be a good extension.