项目作者: takenobu-hs

项目描述 :
command-line Haskell with 'ghc -e'
高级语言:
项目地址: git://github.com/takenobu-hs/commandline-haskell.git
创建时间: 2017-08-10T12:25:39Z
项目社区:https://github.com/takenobu-hs/commandline-haskell

开源协议:

下载


command-line Haskell with ‘ghc -e’

Introduction

The GHC (Glasgow Haskell Compiler) is a enormous and powerful compiler of Haskell.
However, it is also a handy tool like sed and awk. You can use GHC in your daily work :)
For example, it can be embedded in a shell script, it can be executed immediately on your terminal.

One-liners mode (expression evaluation mode) of GHC

The GHC could evaluate a single expression on your shell (see also):

  1. $ ghc -e expr

Cooking recipes

Do you want a calculator? OK, here:

  1. $ ghc -e '1+2'
  2. 3

Do you need sequence data?, please:

  1. $ ghc -e '[1..10]'
  2. [1,2,3,4,5,6,7,8,9,10]

List comprehension is OK (see also):

  1. $ ghc -e '[x^2 | x <- [1..10]]'
  2. [1,4,9,16,25,36,49,64,81,100]

If you want to output per line (see also):

  1. $ ghc -e 'mapM_ print [1..3]'
  2. 1
  3. 2
  4. 3

Actually, you can also use input here:

  1. $ ghc -e 'getLine'
  2. ABC
  3. "ABC"

Of course you can also input and output:

  1. $ ghc -e 'getLine >>= putStrLn'
  2. ABC
  3. ABC

You can also use the do notation to describe the above:

  1. $ ghc -e 'do {x <- getLine; putStrLn x}'
  2. ABC
  3. ABC

Since you can input and output, you can also create a filter:

  1. $ ghc -e 'interact $ unlines . map ("hello " ++) . lines'
  2. John
  3. hello John
  4. Mike
  5. hello Mike

Numeric filter is also OK:

  1. $ cat test.dat # data file for example
  2. 1
  3. 2
  4. 3
  1. $ cat test.dat | ghc -e 'interact $ unlines . map (show . (*2) . (read::String -> Int)) . lines'
  2. 2
  3. 4
  4. 6

Pipeline between GHC and GHC :)

  1. $ ghc -e 'mapM_ print [1..3]' | ghc -e 'interact $ unlines . map ("hello " ++) . lines'
  2. hello 1
  3. hello 2
  4. hello 3

By the way, don’t you want pair data? That’s OK, too:

  1. $ ghc -e "zip [1..3] ['A'..]"
  2. [(1,'A'),(2,'B'),(3,'C')]

Not a pair, but a combination? OK easy (see also):

  1. $ ghc -e "(,) <$> [1..3] <*> ['A'..'C']"
  2. [(1,'A'),(1,'B'),(1,'C'),(2,'A'),(2,'B'),(2,'C'),(3,'A'),(3,'B'),(3,'C')]

Combination of character string and number:

  1. $ ghc -e '(++) <$> ["R", "G", "B"] <*> map show [0..3]'
  2. ["R0","R1","R2","R3","G0","G1","G2","G3","B0","B1","B2","B3"]

Want to generate date strings? :

  1. $ ghc -e '(++) <$> ["2016", "2017", "2018"] <*> ["Jan", "Feb", "Mar"]'
  2. ["2016Jan","2016Feb","2016Mar","2017Jan","2017Feb","2017Mar","2018Jan","2018Feb","2018Mar"]

Let’s insert hyphens:

  1. $ ghc -e '(\x y -> x ++ "-" ++ y) <$> ["2016", "2017", "2018"] <*> ["Jan", "Feb", "Mar"]'
  2. ["2016-Jan","2016-Feb","2016-Mar","2017-Jan","2017-Feb","2017-Mar","2018-Jan","2018-Feb","2018-Mar"]

Do you want to make CSV data?, OK:

  1. $ ghc -e 'mapM_ putStrLn $ (\x y -> x ++ "," ++ y) <$> ["2016", "2017", "2018"] <*> ["Jan", "Feb", "Mar"]'
  2. 2016,Jan
  3. 2016,Feb
  4. 2016,Mar
  5. 2017,Jan
  6. 2017,Feb
  7. 2017,Mar
  8. 2018,Jan
  9. 2018,Feb
  10. 2018,Mar

Well, do you want to know the type in the expression? You can use typed holes with _ (see also) :

  1. $ ghc -e 'foldl _ 0 [1..5]'
  2. <interactive>:0:7: error:
  3. Found hole: _ :: b -> Integer -> b
  4. Where: b is a rigid type variable bound by
  5. the inferred type of it :: Num b => b at <interactive>:0:1-16
  6. In the first argument of foldl’, namely _
  7. In the expression: foldl _ 0 [1 .. 5]
  8. In an equation for it’: it = foldl _ 0 [1 .. 5]
  9. Relevant bindings include it :: b (bound at <interactive>:0:1)

Actually, you can use the ghci command :t(:type) if you want to know the type (see also):

  1. $ ghc -e ':t foldl'
  2. foldl :: Foldable t => (b -> a -> b) -> b -> t a -> b

If it is GHC 8.2 or later, you can use :t +d(:type +d) command for a more simple representation (see also):

  1. $ ghc -e ':t +d foldl'
  2. foldl :: (b -> a -> b) -> b -> [a] -> b

You can also use the :i(:info) command:

  1. $ ghc -e ':i foldl'
  2. class Foldable (t :: * -> *) where
  3. ...
  4. foldl :: (b -> a -> b) -> b -> t a -> b
  5. ...
  6. -- Defined in Data.Foldable

You can also know the kind by :k(:kind) command (see also):

  1. $ ghc -e ':k Maybe'
  2. Maybe :: * -> *

By the way, you can also use quasi-quarts with shell variables! Tiny templating :)

  1. $ NUM=5
  2. $ ghc -e "[1..$NUM]"
  3. [1,2,3,4,5]

You can pass data easily:

  1. $ X1="[1..3]"
  2. $ X2="['A'..'C']"
  3. $ ghc -e "zip $X1 $X2"
  4. [(1,'A'),(2,'B'),(3,'C')]

Other miscellaneous recipes

  1. $ NUMS="[1..3]"
  2. $ ghc -e "sum $NUMS"
  3. 6
  1. $ cat test.dat # data file for example
  2. 1
  3. 2
  4. 3
  5. $ cat test.dat | ghc -e "lines <$> getContents"
  6. ["1","2","3"]
  1. $ cat test.dat | ghc -e "(sum . map read .lines) <$> getContents"
  2. 6
  1. cat test.dat | ghc -e "(filter (>=2) . map read .lines) <$> getContents"
  2. [2,3]
  1. $ ghc -e "let x = 1; y = 2 in x+y"
  2. 3
  1. $ ghc -e 'Text.Printf.printf "%s %d\n" "abc" 1'
  2. abc 1
  1. $ cat .ghci
  2. import Text.Printf
  3. $ ghc -e 'printf "%s %d\n" "abc" 1'
  4. abc
  1. $ ghc -e "sin (pi/4)"
  2. 0.7071067811865475
  1. $ ghc -e "[sin (n * pi/8) | n <- [0..4]]"
  2. [0.0,0.3826834323650898,0.7071067811865475,0.9238795325112867,1.0]
  1. $ ghc -e 'replicate 5 "hello"'
  2. ["hello","hello","hello","hello","hello"]

Let’s enjoy cooking!

References