2 Module : Gargantext.Prelude
3 Description : Specific Prelude of the project
4 Copyright : (c) CNRS, 2017-Present
5 License : AGPL + CECILL v3
6 Maintainer : team@gargantext.org
7 Stability : experimental
12 {-# OPTIONS_GHC -fno-warn-name-shadowing #-}
13 {-# OPTIONS_GHC -fno-warn-type-defaults #-}
15 {-# LANGUAGE FlexibleContexts #-}
16 {-# LANGUAGE NoImplicitPrelude #-}
17 {-# LANGUAGE OverloadedStrings #-}
18 {-# LANGUAGE RankNTypes #-}
20 module Gargantext.Prelude
21 ( module Gargantext.Prelude
24 , module GHC.Err.Located
37 import Control.Monad.Base (MonadBase(..))
38 import GHC.Exts (sortWith)
39 import GHC.Err.Located (undefined)
40 import GHC.Real (round)
41 import Data.Map (Map, lookup)
42 import Data.Maybe (isJust, fromJust, maybe)
43 import Data.Text (Text)
44 import Protolude ( Bool(True, False), Int, Int64, Double, Integer
45 , Fractional, Num, Maybe(Just,Nothing)
46 , Enum, Bounded, Float
48 , pure, (>>=), (=<<), (<*>), (<$>), (>>)
50 , Ord, Integral, Foldable, RealFrac, Monad, filter
51 , reverse, map, mapM, zip, drop, take, zipWith
52 , sum, fromIntegral, length, fmap, foldl, foldl'
53 , takeWhile, sqrt, identity
54 , abs, min, max, maximum, minimum, return, snd, truncate
55 , (+), (*), (/), (-), (.), ($), (&), (**), (^), (<), (>), log
56 , Eq, (==), (>=), (<=), (<>), (/=)
57 , (&&), (||), not, any, all
60 , elem, die, mod, div, const, either
61 , curry, uncurry, repeat
69 import Prelude (Enum, Bounded, minBound, maxBound, putStrLn)
70 -- TODO import functions optimized in Utils.Count
71 -- import Protolude hiding (head, last, all, any, sum, product, length)
72 -- import Gargantext.Utils.Count
73 import qualified Data.List as L hiding (head, sum)
74 import qualified Control.Monad as M
77 import qualified Data.Map as M
79 import Data.Map.Strict (insertWith)
80 import qualified Data.Vector as V
81 import Safe (headMay, lastMay, initMay, tailMay)
82 import Text.Show (Show(), show)
83 import Text.Read (Read())
84 import Data.String.Conversions (cs)
87 printDebug :: (Show a, MonadBase IO m) => [Char] -> a -> m ()
88 printDebug msg x = liftBase . putStrLn $ msg <> " " <> show x
89 -- printDebug _ _ = pure ()
92 -- | splitEvery n == chunkAlong n n
93 splitEvery :: Int -> [a] -> [[a]]
96 let (h,t) = L.splitAt n xs
102 -- | Function to split a range into chunks
103 -- if step == grain then linearity (splitEvery)
104 -- elif step < grain then overlapping
105 -- else dotted with holes
106 -- TODO FIX BUG if Steps*Grain /= length l
107 -- chunkAlong 10 10 [1..15] == [1..10]
108 -- BUG: what about the rest of (divMod 15 10)?
109 -- TODO: chunkAlongNoRest or chunkAlongWithRest
110 -- default behavior: NoRest
112 chunkAlong :: Eq a => Grain -> Step -> [a] -> [[a]]
113 chunkAlong a b l = case a >= length l of
115 False -> chunkAlong' a b l
117 chunkAlong' :: Eq a => Grain -> Step -> [a] -> [[a]]
118 chunkAlong' a b l = case a > 0 && b > 0 of
119 True -> chunkAlong'' a b l
120 False -> panic "ChunkAlong: Parameters should be > 0 and Grain > Step"
122 chunkAlong'' :: Eq a => Int -> Int -> [a] -> [[a]]
123 chunkAlong'' a b l = filter (/= []) $ only (while dropAlong)
126 while = takeWhile (\x -> length x >= a)
127 dropAlong = L.scanl (\x _y -> drop b x) l ([1..] :: [Integer])
129 -- | Optimized version (Vector)
130 chunkAlongV :: Int -> Int -> V.Vector a -> V.Vector (V.Vector a)
131 chunkAlongV a b l = only (while dropAlong)
133 only = V.map (V.take a)
134 while = V.takeWhile (\x -> V.length x >= a)
135 dropAlong = V.scanl (\x _y -> V.drop b x) l (V.fromList [1..])
137 -- | TODO Inverse of chunk ? unchunkAlong ?
138 -- unchunkAlong :: Int -> Int -> [[a]] -> [a]
139 -- unchunkAlong = undefined
142 -- splitAlong [2,3,4] ("helloworld" :: [Char]) == ["he", "llo", "worl", "d"]
143 splitAlong :: [Int] -> [Char] -> [[Char]]
144 splitAlong _ [] = [] -- No list? done
145 splitAlong [] xs = [xs] -- No place to split at? Return the remainder
146 splitAlong (x:xs) ys = take x ys : splitAlong xs (drop x ys)
147 -- take until our split spot, recurse with next split spot and list remainder
149 takeWhileM :: (Monad m) => (a -> Bool) -> [m a] -> m [a]
150 takeWhileM _ [] = return []
151 takeWhileM p (a:as) = do
155 vs <- takeWhileM p as
160 -- To select the right algorithme according to the type:
161 -- https://github.com/mikeizbicki/ifcxt
163 sumSimple :: Num a => [a] -> a
164 sumSimple = L.foldl' (+) 0
166 -- | https://en.wikipedia.org/wiki/Kahan_summation_algorithm
167 sumKahan :: Num a => [a] -> a
168 sumKahan = snd . L.foldl' go (0,0)
170 go (c,t) i = ((t'-t)-y,t')
175 -- | compute part of the dict
176 count2map :: (Ord k, Foldable t) => t k -> Map k Double
177 count2map xs = M.map (/ (fromIntegral (length xs))) (count2map' xs)
179 -- | insert in a dict
180 count2map' :: (Ord k, Foldable t) => t k -> Map k Double
181 count2map' xs = L.foldl' (\x y -> insertWith (+) y 1 x) M.empty xs
183 trunc :: (RealFrac a, Integral c, Integral b) => b -> a -> c
184 trunc n = truncate . (* 10^n)
186 trunc' :: Int -> Double -> Double
187 trunc' n x = fromIntegral $ truncate $ (x * 10^n)
189 ------------------------------------------------------------------------
190 bool2num :: Num a => Bool -> a
194 bool2double :: Bool -> Double
195 bool2double = bool2num
197 bool2int :: Bool -> Int
199 ------------------------------------------------------------------------
201 -- Normalizing && scaling data
202 scale :: [Double] -> [Double]
205 scaleMinMax :: [Double] -> [Double]
206 scaleMinMax xs = map (\x -> (x - mi / (ma - mi + 1) )) xs'
212 scaleNormalize :: [Double] -> [Double]
213 scaleNormalize xs = map (\x -> (x - v / (m + 1))) xs'
219 normalize :: [Double] -> [Double]
220 normalize as = normalizeWith identity as
222 normalizeWith :: Fractional b => (a -> b) -> [a] -> [b]
223 normalizeWith extract bs = map (\x -> x/(sum bs')) bs'
227 -- Zip functions to add
228 zipFst :: ([b] -> [a]) -> [b] -> [(a, b)]
229 zipFst f xs = zip (f xs) xs
231 zipSnd :: ([a] -> [b]) -> [a] -> [(a, b)]
232 zipSnd f xs = zip xs (f xs)
235 maximumWith :: (Ord a1, Foldable t) => (a2 -> a1) -> t a2 -> a2
236 maximumWith f = L.maximumBy (compare `on` f)
238 -- | To get all combinations of a list with no
239 -- repetition and apply a function to the resulting list of pairs
240 listToCombi :: forall a b. (a -> b) -> [a] -> [(b,b)]
241 listToCombi f l = [ (f x, f y) | (x:rest) <- L.tails l, y <- rest ]
243 ------------------------------------------------------------------------
244 -- Empty List Sugar Error Handling
245 -- TODO add Garg Monad Errors
247 listSafe1 :: Text -> ([a] -> Maybe a)
249 listSafe1 s f e xs = maybe (panic $ h <> e) identity (f xs)
251 h = "[ERR][Gargantext] Empty list for " <> s <> " in "
253 head' :: Text -> [a] -> a
254 head' = listSafe1 "head" headMay
256 last' :: Text -> [a] -> a
257 last' = listSafe1 "last" lastMay
259 ------------------------------------------------------------------------
261 listSafeN :: Text -> ([a] -> Maybe [a])
262 -> Text -> [a] -> [a]
263 listSafeN s f e xs = maybe (panic $ h <> e) identity (f xs)
265 h = "[ERR][Gargantext] Empty list for " <> s <> " in "
267 tail' :: Text -> [a] -> [a]
268 tail' = listSafeN "tail" tailMay
270 init' :: Text -> [a] -> [a]
271 init' = listSafeN "init" initMay
273 ------------------------------------------------------------------------
274 --- Some Statistics sugar functions
275 -- Exponential Average
276 eavg :: [Double] -> Double
277 eavg (x:xs) = a*x + (1-a)*(eavg xs)
282 mean :: Fractional a => [a] -> a
283 mean xs = sum xs / fromIntegral (length xs)
285 sumMaybe :: Num a => [Maybe a] -> Maybe a
286 sumMaybe = fmap sum . M.sequence
288 variance :: Floating a => [a] -> a
289 variance xs = sum ys / (fromIntegral (length xs) - 1)
292 ys = map (\x -> (x - m) ** 2) xs
294 deviation :: Floating a => [a] -> a
295 deviation = sqrt . variance
297 movingAverage :: (Eq b, Fractional b) => Int -> [b] -> [b]
298 movingAverage steps xs = map mean $ chunkAlong steps 1 xs
300 ma :: [Double] -> [Double]
303 -----------------------------------------------------------------------
307 fib n = fib (n-1) + fib (n-2)
310 -----------------------------------------------------------------------
311 --- Map in Map = Map2
312 -- To avoid Map (a,a) b
313 type Map2 a b = Map a (Map a b)