└── 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 |
--------------------------------------------------------------------------------