The problem with shell scripting
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—or similar languages—as a shell scripting language?
Using GHCI for System Programing
Setup
-
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 ) hsh_extend ${OPTARG} eesac 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.
The Good
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.
The Bad
- No Tab-Completion for commands/paths
- No Syntax-Highlighting
Bonus Round
Launching GHCI Directly in Your Terminal Emulator
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.
Future Work
ptghci adds useful features like syntax highlighting and tab completion and might be a good extension.
SOURCES
- https://downloads.haskell.org/~ghc/7.6.3/docs/html/users_guide/ghci-dot-files.html
- https://bobkonf.de/2017/slides/thoma.pdf