Skip to content

Instantly share code, notes, and snippets.

@fkurz
Last active February 17, 2021 14:40
Show Gist options
  • Select an option

  • Save fkurz/cf00cf22acb6f40879c47e34074f991a to your computer and use it in GitHub Desktop.

Select an option

Save fkurz/cf00cf22acb6f40879c47e34074f991a to your computer and use it in GitHub Desktop.
Haskell Shell Scripting with GHCI and Turtle

Shell scripting with Haskell

Problem

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?

Using GHCI for System Programing

Setup

  1. Install Haskell Stack

    brew install haskell-stack
  2. Install turtle using Stack

    stack install turtle
  3. 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
  4. Run Haskell Shell and have fun 馃檶

    $ hsh -e git 
    [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 two very cool aspects of Haskell/GHCI that are being used here:

  1. monads: most Turtle functions like dir and echo 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
    位> dir
    FilePath "/Users/friedrichk/.hsh"
  2. overloaded strings:

    • E.g. echo has type echo :: MonadIO io => Line -> io () (i.e. expects Line not String) which can however use the overloaded string literal syntax
    > echo "Hi!"
  3. printing of return values: return of echo is something that is printable and GHCI therefore prints it nicely

    > echo "Hi!"
    Hi!

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 Shell feeling.

Future Work

ptghci adds useful features like syntax highlighting and tab completion and might be a good extension.


SOURCES

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment