└── README.md /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 | command-line Haskell with 'ghc -e' 4 | ================================== 5 | 6 | 7 | Introduction 8 | ------------ 9 | 10 | The [GHC](https://www.haskell.org/ghc/) (Glasgow Haskell Compiler) is a enormous and powerful compiler of [Haskell](https://www.haskell.org/). 11 | However, it is also a handy tool like sed and awk. You can use GHC in your daily work :) 12 | For example, it can be embedded in a shell script, it can be executed immediately on your terminal. 13 | 14 | 15 | One-liners mode (expression evaluation mode) of GHC 16 | --------------------------------------------------- 17 | 18 | The GHC could evaluate a single expression on your shell ([see also](https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/using.html#expression-evaluation-mode)): 19 | 20 | ``` 21 | $ ghc -e expr 22 | ``` 23 | 24 | 25 | Cooking recipes 26 | --------------- 27 | 28 | Do you want a calculator? OK, here: 29 | ``` 30 | $ ghc -e '1+2' 31 | 3 32 | ``` 33 | 34 | Do you need sequence data?, please: 35 | ``` 36 | $ ghc -e '[1..10]' 37 | [1,2,3,4,5,6,7,8,9,10] 38 | ``` 39 | 40 | List comprehension is OK ([see also](http://learnyouahaskell.com/starting-out#im-a-list-comprehension)): 41 | ``` 42 | $ ghc -e '[x^2 | x <- [1..10]]' 43 | [1,4,9,16,25,36,49,64,81,100] 44 | ``` 45 | 46 | If you want to output per line ([see also](http://learnyouahaskell.com/input-and-output#hello-world)): 47 | ``` 48 | $ ghc -e 'mapM_ print [1..3]' 49 | 1 50 | 2 51 | 3 52 | ``` 53 | 54 | 55 | Actually, you can also use input here: 56 | ``` 57 | $ ghc -e 'getLine' 58 | ABC 59 | "ABC" 60 | ``` 61 | 62 | Of course you can also input and output: 63 | ``` 64 | $ ghc -e 'getLine >>= putStrLn' 65 | ABC 66 | ABC 67 | ``` 68 | 69 | You can also use the do notation to describe the above: 70 | ``` 71 | $ ghc -e 'do {x <- getLine; putStrLn x}' 72 | ABC 73 | ABC 74 | ``` 75 | 76 | Since you can input and output, you can also create a filter: 77 | ``` 78 | $ ghc -e 'interact $ unlines . map ("hello " ++) . lines' 79 | John 80 | hello John 81 | Mike 82 | hello Mike 83 | ``` 84 | 85 | Numeric filter is also OK: 86 | ``` 87 | $ cat test.dat # data file for example 88 | 1 89 | 2 90 | 3 91 | ``` 92 | 93 | ``` 94 | $ cat test.dat | ghc -e 'interact $ unlines . map (show . (*2) . (read::String -> Int)) . lines' 95 | 2 96 | 4 97 | 6 98 | ``` 99 | 100 | Pipeline between GHC and GHC :) 101 | ``` 102 | $ ghc -e 'mapM_ print [1..3]' | ghc -e 'interact $ unlines . map ("hello " ++) . lines' 103 | hello 1 104 | hello 2 105 | hello 3 106 | ``` 107 | 108 | 109 | By the way, don't you want pair data? That's OK, too: 110 | ``` 111 | $ ghc -e "zip [1..3] ['A'..]" 112 | [(1,'A'),(2,'B'),(3,'C')] 113 | ``` 114 | 115 | Not a pair, but a combination? OK easy ([see also](http://learnyouahaskell.com/functors-applicative-functors-and-monoids#applicative-functors)): 116 | ``` 117 | $ ghc -e "(,) <$> [1..3] <*> ['A'..'C']" 118 | [(1,'A'),(1,'B'),(1,'C'),(2,'A'),(2,'B'),(2,'C'),(3,'A'),(3,'B'),(3,'C')] 119 | ``` 120 | 121 | Combination of character string and number: 122 | ``` 123 | $ ghc -e '(++) <$> ["R", "G", "B"] <*> map show [0..3]' 124 | ["R0","R1","R2","R3","G0","G1","G2","G3","B0","B1","B2","B3"] 125 | ``` 126 | 127 | Want to generate date strings? : 128 | ``` 129 | $ ghc -e '(++) <$> ["2016", "2017", "2018"] <*> ["Jan", "Feb", "Mar"]' 130 | ["2016Jan","2016Feb","2016Mar","2017Jan","2017Feb","2017Mar","2018Jan","2018Feb","2018Mar"] 131 | 132 | ``` 133 | 134 | Let's insert hyphens: 135 | ``` 136 | $ ghc -e '(\x y -> x ++ "-" ++ y) <$> ["2016", "2017", "2018"] <*> ["Jan", "Feb", "Mar"]' 137 | ["2016-Jan","2016-Feb","2016-Mar","2017-Jan","2017-Feb","2017-Mar","2018-Jan","2018-Feb","2018-Mar"] 138 | ``` 139 | 140 | Do you want to make CSV data?, OK: 141 | ``` 142 | $ ghc -e 'mapM_ putStrLn $ (\x y -> x ++ "," ++ y) <$> ["2016", "2017", "2018"] <*> ["Jan", "Feb", "Mar"]' 143 | 2016,Jan 144 | 2016,Feb 145 | 2016,Mar 146 | 2017,Jan 147 | 2017,Feb 148 | 2017,Mar 149 | 2018,Jan 150 | 2018,Feb 151 | 2018,Mar 152 | ``` 153 | 154 | 155 | Well, do you want to know the type in the expression? You can use typed holes with `_` ([see also](https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/glasgow_exts.html#typed-holes)) : 156 | ``` 157 | $ ghc -e 'foldl _ 0 [1..5]' 158 | 159 | :0:7: error: 160 | • Found hole: _ :: b -> Integer -> b 161 | Where: ‘b’ is a rigid type variable bound by 162 | the inferred type of it :: Num b => b at :0:1-16 163 | • In the first argument of ‘foldl’, namely ‘_’ 164 | In the expression: foldl _ 0 [1 .. 5] 165 | In an equation for ‘it’: it = foldl _ 0 [1 .. 5] 166 | • Relevant bindings include it :: b (bound at :0:1) 167 | ``` 168 | 169 | Actually, you can use the ghci command `:t`(:type) if you want to know the type ([see also](https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/ghci.html#ghci-cmd-:type)): 170 | ``` 171 | $ ghc -e ':t foldl' 172 | foldl :: Foldable t => (b -> a -> b) -> b -> t a -> b 173 | ``` 174 | 175 | If it is GHC 8.2 or later, you can use `:t +d`(:type +d) command for a more simple representation ([see also](https://downloads.haskell.org/%7Eghc/latest/docs/html/users_guide/ghci.html#ghci-cmd-:type%20+d%20%E2%9F%A8expression%E2%9F%A9)): 176 | ``` 177 | $ ghc -e ':t +d foldl' 178 | foldl :: (b -> a -> b) -> b -> [a] -> b 179 | ``` 180 | 181 | You can also use the `:i`(:info) command: 182 | ``` 183 | $ ghc -e ':i foldl' 184 | class Foldable (t :: * -> *) where 185 | ... 186 | foldl :: (b -> a -> b) -> b -> t a -> b 187 | ... 188 | -- Defined in ‘Data.Foldable’ 189 | ``` 190 | 191 | You can also know the kind by `:k`(:kind) command ([see also](http://learnyouahaskell.com/making-our-own-types-and-typeclasses#kinds-and-some-type-foo)): 192 | ``` 193 | $ ghc -e ':k Maybe' 194 | Maybe :: * -> * 195 | ``` 196 | 197 | 198 | By the way, you can also use quasi-quarts with shell variables! Tiny templating :) 199 | ``` 200 | $ NUM=5 201 | $ ghc -e "[1..$NUM]" 202 | [1,2,3,4,5] 203 | ``` 204 | 205 | You can pass data easily: 206 | ``` 207 | $ X1="[1..3]" 208 | $ X2="['A'..'C']" 209 | $ ghc -e "zip $X1 $X2" 210 | [(1,'A'),(2,'B'),(3,'C')] 211 | ``` 212 | 213 | 214 | Other miscellaneous recipes 215 | --------------------------- 216 | 217 | ``` 218 | $ NUMS="[1..3]" 219 | $ ghc -e "sum $NUMS" 220 | 6 221 | ``` 222 | 223 | ``` 224 | $ cat test.dat # data file for example 225 | 1 226 | 2 227 | 3 228 | 229 | $ cat test.dat | ghc -e "lines <$> getContents" 230 | ["1","2","3"] 231 | ``` 232 | 233 | ``` 234 | $ cat test.dat | ghc -e "(sum . map read .lines) <$> getContents" 235 | 6 236 | ``` 237 | 238 | ``` 239 | cat test.dat | ghc -e "(filter (>=2) . map read .lines) <$> getContents" 240 | [2,3] 241 | ``` 242 | 243 | ``` 244 | $ ghc -e "let x = 1; y = 2 in x+y" 245 | 3 246 | ``` 247 | 248 | ``` 249 | $ ghc -e 'Text.Printf.printf "%s %d\n" "abc" 1' 250 | abc 1 251 | ``` 252 | 253 | ``` 254 | $ cat .ghci 255 | import Text.Printf 256 | 257 | $ ghc -e 'printf "%s %d\n" "abc" 1' 258 | abc 259 | ``` 260 | 261 | ``` 262 | $ ghc -e "sin (pi/4)" 263 | 0.7071067811865475 264 | ``` 265 | 266 | ``` 267 | $ ghc -e "[sin (n * pi/8) | n <- [0..4]]" 268 | [0.0,0.3826834323650898,0.7071067811865475,0.9238795325112867,1.0] 269 | ``` 270 | 271 | ``` 272 | $ ghc -e 'replicate 5 "hello"' 273 | ["hello","hello","hello","hello","hello"] 274 | ``` 275 | 276 | Let's enjoy cooking! 277 | 278 | 279 | References 280 | ---------- 281 | 282 | * [GHC User’s Guide](https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/) 283 | * [Haskell.org](https://www.haskell.org/) 284 | * [Haskell 2010 Language Report](https://www.haskell.org/onlinereport/haskell2010/) 285 | * [The Glasgow Haskell Compiler](https://www.haskell.org/ghc/) 286 | * [Learn You a Haskell for Great Good!](http://learnyouahaskell.com/) 287 | 288 | --------------------------------------------------------------------------------