-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathUtils.hs
176 lines (134 loc) · 4.64 KB
/
Utils.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
module Utils where
import Data.List (group, sort)
import qualified Data.Map as Map
import Data.Maybe
--import Control.Parallel.Strategies (parMap, rseq)
-------------
-- Reading --
-------------
readInt = (read :: String -> Int)
readInteger = (read :: String -> Integer)
readDouble = (read :: String -> Double)
readDigits :: String -> [Int]
readDigits = map (readInt . (:[]))
------------
-- Tuples --
------------
tuplify2 [a, b] = (a, b)
tuplify3 [a, b, c] = (a, b, c)
tuplify4 [a, b, c, d] = (a, b, c, d)
listify2 (a, b) = [a, b]
listify3 (a, b, c) = [a, b, c]
listify4 (a, b, c, d) = [a, b, c, d]
fst3 (a, _, _) = a
snd3 (_, b, _) = b
thi3 (_, _, c) = c
fst4 (a, _, _, _) = a
snd4 (_, b, _, _) = b
thi4 (_, _, c, _) = c
fou4 (_, _, _, d) = d
-----------
-- Lists --
-----------
-- A faster nub, which, however, requires an order and is unstable.
-- O(n*log n) instead of O(n^2).
fastNub :: Ord a => [a] -> [a]
fastNub = map head . group . sort
-- Like !!, but inverse
at :: Int -> [a] -> a
at = flip (!!)
-- This should actually be present in the base lib, but isn't.
-- Total version of !!.
(!?) :: [a] -> Int -> Maybe a
[] !? _ = Nothing
(x:_) !? 0 = Just x
(_:xs) !? n = xs !? (n-1)
-- Cartesian product of two lists
cart :: [a] -> [b] -> [(a,b)]
cart x y = (,) <$> x <*> y
-- Like dropWhile, but also drops the first element
-- that does not fulfill the predicate any more.
dropWhile1 :: Eq a => (a -> Bool) -> [a] -> [a]
dropWhile1 p = drop 1 . dropWhile p
-- Find the first recurring element and return
-- the index of its first and its second occurrence
firstRecur :: Ord a => [a] -> Maybe (Int, Int)
firstRecur = go Map.empty 0
where
go _ _ [] = Nothing
go seen i (x:xs) = case (Map.lookup x seen) of
Just j -> Just (j,i)
Nothing -> go (Map.insert x i seen) (i+1) xs
-- Group a list into a list of sublist of length n.
-- The last sublist may be shorter than n.
groupn :: Int -> [a] -> [[a]]
groupn _ [] = []
groupn n xs = (take n xs) : groupn n xs'
where
xs' = drop n xs
-- Tokenise an array into a list of arrays based on delimiters
-- Multiple delimiters are considered as one delimiter.
-- Delimiters at the beginning and end are ignored
tok :: Eq a => [a] -> [a] -> [[a]]
tok _ [] = []
tok delims input@(x:xs)
| isDelimiter x = tok delims xs
| otherwise = curToken : tok delims input'
where
isDelimiter = (`elem` delims)
curToken = takeWhile (not . isDelimiter) input
input' = dropWhile isDelimiter $ dropWhile (not . isDelimiter) input
-- 2d map, i.e. apply a function to all elements of all lists inside a list.
map2 :: (a -> b) -> [[a]] -> [[b]]
map2 f = map (map f)
-- Insert an element into a list at the given position.
push :: Int -> a -> [a] -> [a]
push i x xs = left ++ [x] ++ right
where
left = take i xs
right = drop i xs
-- Remove the i-th element of a given list xs.
pop :: Int -> [a] -> [a]
pop i xs = (take i xs) ++ (drop (i + 1) xs)
-- Count how many element of a list fulfil a predicate.
countTrue :: (a -> Bool) -> [a] -> Int
countTrue p = length . filter p
-- Count how often a list occurs within another list.
countOcc :: Eq a => [a] -> [a] -> Int
countOcc _ [] = 0
countOcc [] _ = error "Utils.countOcc: Empty search list."
countOcc ndl hay
| length ndl > length hay = 0
| ndl == take (length ndl) hay = 1 + countOcc ndl (tail hay)
| otherwise = countOcc ndl (tail hay)
nubByWith :: (a -> a -> Bool) -> ([a] -> a) -> [a] -> [a]
nubByWith eq agg = go
where
go [] = []
go elems@(x:_) = agg (filter (\ e -> x `eq` e) elems)
: go (filter (\ e -> not (x `eq` e)) elems)
-----------------
-- Arrow Stuff --
-----------------
-- Transform function s.t. it operates on the first element of a 2-tuple
first :: (a -> c) -> (a, b) -> (c, b)
first = \f (x, y) -> (f x, y)
-- Transform function s.t. it operates on the second element of a 2-tuple
second :: (b -> c) -> (a, b) -> (a, c)
second = \f (x, y) -> (x, f y)
-- Fanout: Two functions operate on the same input, yielding a 2-tuple
(&&&) :: (a -> b) -> (a -> c) -> a -> (b, c)
(&&&) = \f g x -> (f x, g x)
-- Split: Two functions operating "in parallel" on a 2-tuple
(***) :: (a -> c) -> (b -> d) -> (a, b) -> (c, d)
(***) = \f g (x, y) -> (f x, g y)
----------------------------
-- Simple Parallelisation --
----------------------------
-- Syntactic sugar
--pmap :: (a -> b) -> [a] -> [b]
--pmap = parMap rseq
-- Assuming the evaluation function is costly,
-- we need to execute it in parallel.
--pfilter :: (a -> Bool) -> [a] -> [a]
--pfilter p = concat . pmap (\ x -> if p x then [x] else [])