This is a collection of useful short code snippets.
Haskell doesn’t have a native Pipe operator like F# (F-Sharp) does, however it can be defined by the user.
> let (|>) x f = f x
>
> let (|>>) x f = map f x
> let (?>>) x f = filter f x
> take 3 (reverse (filter even [1..10]))
[10,8,6]
> [1..10] |> filter even |> reverse |> take 3
[10,8,6]
>
> [1..10] |>> (^2) |>> (/10) |>> (+100)
[100.1,100.4,100.9,101.6,102.5,103.6,104.9,106.4,108.1,110.0]
>
> [1..10] ?>> even
[2,4,6,8,10]
>
> [1..10] ?>> even |>> (+1)
[3,5,7,9,11]
>
>
Definition:
pairs alist = zip alist (tail alist)
The pairs iterator converts a list of elements to a new list of consecutive elements tuple.
Pseudo code:
pairs [e0, e1, e2, e3, e4 ...] ==> [(e0, e1), (e1, e2), (e3, e4) ...]
Let f be a function of two arguments:
f :: a -> a -> b
The function f can be applied to to the pairs sequence using the higher order function uncurry.
Pseudo code:
> g = uncurry(f) :: (a, a) -> b > g (x, y) = f x y > map uncurry(f) $ pairs [e0, e1, e2, e3, e4 ...] > [g (e0, e1), g (e1, e2), g (e2, e3), g (e3, e4) ...]
It can be useful to calculate the distance between two points, lagged difference, growth of a time series, draw a line between each two consecutive points or apply any function to two consecutive elements.
Example: Grouping Consecutive numbers
> let pairs alist = zip alist (tail alist)
> pairs [1..5]
[(1,2),(2,3),(3,4),(4,5)]
Example: Lagged Difference
Pseudo code:
lagdiff [e0, e1, e2, e3, e4 ...] ==> [(e1 - e0), (e2 - e1), (e3 - e2) ... ]
Development:
> let pairs alist = zip alist (tail alist)
> :t pairs
pairs :: [b] -> [(b, b)]
> :t (-)
(-) :: Num a => a -> a -> a
> :t uncurry(-)
uncurry(-) :: Num c => (c, c) -> c
>
> (-) 20 10
10
>
> uncurry(-) (20, 10)
10
>
> uncurry(-) (10, 20)
-10
>
> uncurry(flip (-)) (10, 20)
10
>
> pairs [10.3, 20.5, 5.6, 8.23, 40.3]
[(10.3,20.5),(20.5,5.6),(5.6,8.23),(8.23,40.3)]
>
> map (uncurry ( flip (-))) $ pairs [10.3, 20.5, 5.6, 8.23, 40.3]
[10.2,-14.9,2.630000000000001,32.06999999999999]
>
> let lagdiff series = map (uncurry ( flip (-))) $ pairs series
> :t lagdiff
lagdiff :: Num b => [b] -> [b]
>
> lagdiff [10.3, 20.5, 5.6, 8.23, 40.3]
[10.2,-14.9,2.630000000000001,32.06999999999999]
>
> lagdiff [10, 30, 5, 8, 100]
[20,-25,3,92]
>
Example: Distance between points on the plane.
> let pairs alist = zip alist (tail alist)
{- [(X, Y)] coordinates of points in a plane -}
> let points = [(1.0, 2.0), (3.0, 4.0), (-1.0, 5.0), (6.0, 6.0)]
> let distance (x1, y1) (x2, y2) = sqrt( (x2-x1)^2 + (y2-y1)^2 )
> let lines = pairs points
> lines
[((1.0,2.0),(3.0,4.0)),((3.0,4.0),(-1.0,5.0)),((-1.0,5.0),(6.0,6.0))]
>
> distance (1.0, 2.0) (3.0, 4.0)
2.8284271247461903
>
{- Calculate the length of each line segment -}
> map (uncurry(distance)) lines
[2.8284271247461903,4.123105625617661,7.0710678118654755]
>
> sum $ map (uncurry(distance)) lines
14.022600562229327
>
> let totalLength points = sum $ map (uncurry(distance)) $ pairs (points)
>
> totalLength points
14.022600562229327
>
Definition:
triples alist = zip3 alist (tail alist) (tail $ tail alist)
Example:
> triples [1..10]
[(1,2,3),(2,3,4),(3,4,5),(4,5,6),(5,6,7),(6,7,8),(7,8,9),(8,9,10)]
>
> :t triples
triples :: [c] -> [(c, c, c)]
>
>
This iterator is used in Scala and it is a generalized pairs iterator.
Definition:
sliding n alist = map (take n) (take (length(alist) -n + 1 ) $ iterate tail alist)
Example:
> sliding 3 [1..10]
[[1,2,3],[2,3,4],[3,4,5],[4,5,6],[5,6,7],[6,7,8],[7,8,9],[8,9,10]]
> sliding 4 [1..10]
[[1,2,3,4],[2,3,4,5],[3,4,5,6],[4,5,6,7],[5,6,7,8],[6,7,8,9],[7,8,9,10]]
> sliding 5 [1..10]
[[1,2,3,4,5],[2,3,4,5,6],[3,4,5,6,7],[4,5,6,7,8],[5,6,7,8,9],[6,7,8,9,10]]
> sliding 6 [1..10]
[[1,2,3,4,5,6],[2,3,4,5,6,7],[3,4,5,6,7,8],[4,5,6,7,8,9],[5,6,7,8,9,10]]
> sliding 9 [1..10]
[[1,2,3,4,5,6,7,8,9],[2,3,4,5,6,7,8,9,10]]
>
Scala Equivalent
scala> (1 to 5).iterator.sliding(3).toList res2: List[Seq[Int]] = List(List(1, 2, 3), List(2, 3, 4), List(3, 4, 5))
Equivalent to python enumerate.
Definition:
enumerate :: [b] -> [(Int, b)]
enumerate alist = zip [0..(length(alist)-1)] alist
Example:
> enumerate ['a', 'b', 'c', 'd', 'e', 'f']
[(0,'a'),(1,'b'),(2,'c'),(3,'d'),(4,'e'),(5,'f')]
> take 8 (enumerate ['a'..'z'])
[(0,'a'),(1,'b'),(2,'c'),(3,'d'),(4,'e'),(5,'f'),(6,'g'),(7,'h')]
>
Group by length
Definition:
groupByLen n alist = filter (\a -> length(a) == n ) ( map f indexes )
where
len = length(alist)
indexes = map (\i -> n*i) [0..(div len n)]
f idx = take n (drop idx alist)
Example:
> groupByLen 3 [1..15]
[[1,2,3],[4,5,6],[7,8,9],[10,11,12],[13,14,15]]
>
> groupByLen 5 [1..15]
[[1,2,3,4,5],[6,7,8,9,10],[11,12,13,14,15]]
>
> groupByLen 6 [0..20]
[[0,1,2,3,4,5],[6,7,8,9,10,11],[12,13,14,15,16,17]]
>
> groupByLen 3 ['a'..'z']
["abc","def","ghi","jkl","mno","pqr","stu","vwx"]
>
juxt is a function that allows apply a list of functions of same type signature to a single argument. This is useful for numerical analysis, statistics and engineering. This function was taken from the Clojure library.
juxt fs x = map ($ x) fs
Example:
> let juxt fs x = map ($ x) fs > juxt [(*3), (+4), (/10)] 30 [90.0,34.0,3.0] > > let fs = juxt [(*3), (+4), (/10)] > > :t fs fs :: Double -> [Double] > > fs 30 [90.0,34.0,3.0] > fs 40 [120.0,44.0,4.0] > > map fs [10, 20, 30] [[30.0,14.0,1.0],[60.0,24.0,2.0],[90.0,34.0,3.0]] >
The family of functions juxt2, juxt3, juxt4 allow apply tuples of functions to a single argument. This is necessary when the functions don’t have the same type signature.
juxt2 (f1, f2) x = (f1 x, f2 x)
juxt3 (f1, f2, f3) x = (f1 x, f2 x, f3 x)
juxt4 (f1, f2, f3, f4) x = (f1 x, f2 x, f3 x, f4 x)
juxt5 (f1, f2, f3, f4, f5) x = (f1 x, f2 x, f3 x, f4 x, f5 x)
Example:
{-
This function fails in static typed language when
the functions don't have the same type signature
-}
> juxt [(>100), (+100)] 30
<interactive>:36:9:
No instance for (Num Bool) arising from the literal `100'
Possible fix: add an instance declaration for (Num Bool)
In the second argument of `(>)', namely `100'
In the expression: (> 100)
In the first argument of `juxt', namely `[(> 100), (+ 100)]'
> juxt2 ((>100), (+100)) 30
(False,130)
>
>
> let f = juxt2 ((>100), (+100))
> :t f
f :: Integer -> (Bool, Integer)
>
> f 30
(False,130)
>
> map f [10, 20, 25, 30, 100, 150]
[(False,110),(False,120),(False,125),(False,130),(False,200),(True,250)]
>
>
> juxt3 (length, maximum, minimum) [100.23, 23.23, 12.33, -123.23, -1000.23, 4000.5]
(6,4000.5,-1000.23)
>
{-
The type system fails to resolve the types in someone
cases. So when it happens the developer must make the
function types explicit.
-}
> let analytics = juxt3 (length, maximum, minimum)
>
> :t analytics
analytics :: [()] -> (Int, (), ())
>
> analytics [100.23, 23.23, 12.33, -123.23, -1000.23, 4000.5]
<interactive>:79:12:
No instance for (Fractional ()) arising from the literal `100.23'
Possible fix: add an instance declaration for (Fractional ())
In the expression: 100.23
In the first argument of `analytics', namely
`[100.23, 23.23, 12.33, - 123.23, ....]'
In the expression: analytics [100.23, 23.23, 12.33, - 123.23, ....]
> let analytics :: [Double] -> (Int, Double, Double) ; analytics = juxt3 (length, maximum, minimum)
>
> :t analytics
analytics :: [Double] -> (Int, Double, Double)
>
> analytics [100.23, 23.23, 12.33, -123.23, -1000.23, 4000.5]
(6,4000.5,-1000.23)
>
> import Data.Char
>
> let f = juxt3 (succ, pred, ord)
> :t f
f :: Char -> (Char, Char, Int)
>
> let a = map f "haskell is fun"
> a
[('i','g',104),('b','`',97),('t','r',115),('l','j',107),('f','d',101),('m','k',108),('m','k',108),('!','\US',32),('j','h',105),('t','r',115),('!','\US',32),('g','e',102),('v','t',117),('o','m',110)]
>
> unzip3 a
("ibtlfmm!jt!gvo","g`rjdkk\UShr\USetm",[104,97,115,107,101,108,108,32,105,115,32,102,117,110])
>
>
between
between a b x = a <= x && x <= b
> filter (between 10 20) [23, 5, 8, 17, 24, 13, 12]
[17,13,12]
>
> filter (not . between 10 20) [23, 5, 8, 17, 24, 13, 12]
[23,5,8,24]
ifelseDo
Pseudo Code:
f(x) = if pred(x) == True then: fa(x) else fb(x)
ifelseDo pred fa fb x = if pred x then fa x else fb x
Example: Apply the list the function (if x >10 then 10*x else x+5)
> let ifelseDo pred fa fb x = if pred x then fa x else fb x
> map (ifelseDo (>10) (*4) (+5)) [-1, 2, 7, 8, 9, 10, 20, 30, 50]
[4,7,12,13,14,15,80,120,200]
> let f = ifelseDo (>10) (*4) (+5)
> f 1
6
> f 3
8
> f 5
10
>
> f 20
80
> f 30
120
λ> map f [-1, 2, 7, 8, 9, 10, 20, 30, 50]
[4,7,12,13,14,15,80,120,200]
ifelse*
Pseudo Code:
f(x) = if pred(x) == True then: a else b
ifelse pred a b x = if pred x then a else b
Example:
If x<0 set x to -1 else set to 1
> let f = ifelse (<0) (-1) 1
>
> f 2
1
> f 40
1
> f (-1)
-1
> f (-10)
-1
> map f [-1, -2, 3, 4, -5, -6, 0, 2]
[-1,-1,1,1,-1,-1,1,1]
>
ifelseEq
Pseudo Code:
f(x) = if pred(x) == True then: a else x
ifelseEq pred a x = if pred x then a else x
Example: if(x) > 10 then 30 else x
> let ifelseEq pred a x = if pred x then a else x
> let f = ifelseEq (>10) 30
> map f [1, 2, 20, 10, 9, 8, 100]
[1,2,30,10,9,8,30]
>