[!NOTE]
This project is still work in progress. It has a working proof-of-concept (PoC), that was demonstrated at the
MuniHac2024 event.
THSH
THSH (Template Haskell SHell) is a "noDSL" approach to mixing shell scripting with Haskell programs
using Template Haskell.
Key Features
Gradual "Haskellization"
The key goal of the project is to enable a gradual approach to adding strongly-typed Haskell code to enhance your shell
scripting experience.
It is gradual because you can wrap any shell script into a Template Haskell quasi-quotation with thsh
:
#!/usr/bin/env thsh
__main__ = [|thsh\
echo "Hello Haskell!"
|]
Pipe To Haskell Functions
[!WARNING]
The current PoC uses the PyF project's internal code to achieve parsing, which presents difficulty in choosing a
better Haskell code delimiters other than "« ... »", for now. In the next version, a more palatable syntax should be
achieved, e.g. "!{ ... }".
You can pipe the entire outputs from a process to a Haskell function:
#!/usr/bin/env thsh
import Data.Char (toLower)
__main__ = [thsh|\
curl -s https://www.haskell.org/ | «fn (ContentFn $
\content -> "Number of occurrences of the word 'haskell' on haskell.org is "
<> show (length (filter ((== "haskell"). fmap toLower) . words $ content))
<> "\n"
)
»
|]
===>
Number of occurrences of the word 'haskell' on haskell.org is 30
You can also process each line independently:
#!/usr/bin/env thsh
sumSales = LineReadFn
(\ (_ :: String, price, quantity) s -> let s' = s + price * quantity
in (s', Nothing))
(\ s -> Just (show s ++ "\n"))
(0.0 :: Float)
__main__ = [thsh|\
echo -n "Sum of the sales: "; {
# Read (product :: String, price :: Float, quanity :: Float)
«fn sumSales» <<EOF
("apple", 1.2, 100.2)
("orange", 2.0, 34.2)
("pear", 1.2, 62.3)
EOF
} | tail -n1
|]
===>
Sum of the sales: 263.4
[!NOTE]
More pre-defined function patter will be developed.
Composable
The thsh
quoted code can compose with each other:
#!/usr/bin/env thsh
s0 :: Script
s0 = [thsh| bc |]
__main__ = [thsh|\
for i in `seq 0 10`;do
expr="2 ^ $i"
echo -n "$expr = "
echo $expr | «sh s0»
done
|]
|]
-->
= 2
2 ^ 2 = 4
2 ^ 3 = 8
2 ^ 4 = 16
2 ^ 5 = 32
2 ^ 6 = 64
2 ^ 7 = 128
2 ^ 8 = 256
2 ^ 9 = 512
2 ^ 10 = 1024
By default, the "thsh" loader uses the "cabal
run" under the hood. That means that you can use
cabal specific metadata sections for both package-level and project-level:
{- cabal:
build-depends: diagrams
-}
{- project:
optimization: 2
-}
More Examples
You can find more examples available under the "examples" folder.
Comparing To eDSL Solutions
We should note that there have been multiple projects allowing the mixing of Haskell code with shell scripting. All of
them require their users to learn an eDSL of their own.
Here is an incomplete list of these projects:
- hell : Haskell-based shell scripting language.
- turtle : turtle is a reimplementation of the Unix command line
environment in Haskell so that you can use Haskell as both a shell and a scripting language.
- shelly : shell-like (systems) programming in Haskell.
- shh : Simple shell scripting from Haskell.
- HSH : Library to mix shell scripting with Haskell programs.
By now, it should be evident to you that requiring minimum learning of a new eDSL, aka "noDSL" to be tongue-in-cheek,
sets this project apart to offer a viable alternative to Haskell enthusiasts.
TODOs For The Beta (0.0.1.0) Release
Known Bugs and Limitations
Features
Maintainability
DevX