1 {-| Utility functions -}
3 module Ganeti.HTools.Utils
35 import Text.Printf (printf)
39 -- | To be used only for debugging, breaks referential integrity.
40 debug :: Show a => a -> a
41 debug x = trace (show x) x
43 -- | Check if the given argument is Left something
44 isLeft :: Either a b -> Bool
50 fromLeft :: Either a b -> a
51 fromLeft = either (\x -> x) (\_ -> undefined)
53 fromRight :: Either a b -> b
54 fromRight = either (\_ -> undefined) id
56 -- | Comma-join a string list.
57 commaJoin :: [String] -> String
58 commaJoin = intercalate ","
60 -- | Split a string on a separator and return an array.
61 sepSplit :: Char -> String -> [String]
63 | x == "" && xs == [] = []
66 | otherwise = x:(sepSplit sep ys)
67 where (x, xs) = break (== sep) s
70 -- | Partial application of sepSplit to @'.'@
71 commaSplit :: String -> [String]
72 commaSplit = sepSplit ','
74 -- | Swap a list of @(a, b)@ into @(b, a)@
75 swapPairs :: [(a, b)] -> [(b, a)]
76 swapPairs = map (\ (a, b) -> (b, a))
78 -- Simple and slow statistical functions, please replace with better versions
80 -- | Mean value of a list.
81 meanValue :: Floating a => [a] -> a
82 meanValue lst = (sum lst) / (fromIntegral $ length lst)
84 -- | Standard deviation.
85 stdDev :: Floating a => [a] -> a
87 let mv = meanValue lst
88 square = (^ (2::Int)) -- silences "defaulting the constraint..."
89 av = sum $ map square $ map (\e -> e - mv) lst
90 bv = sqrt (av / (fromIntegral $ length lst))
93 -- | Coefficient of variation.
94 varianceCoeff :: Floating a => [a] -> a
95 varianceCoeff lst = (stdDev lst) / (fromIntegral $ length lst)
97 -- | Get a Right result or print the error and exit
98 readData :: (String -> IO (Either String String)) -> String -> IO String
103 putStrLn $ fromLeft nd
104 exitWith $ ExitFailure 1
105 return $ fromRight nd
107 {-- Our cheap monad-like stuff.
109 Thi is needed since Either e a is already a monad instance somewhere
110 in the standard libraries (Control.Monad.Error) and we don't need that
114 combineEithers :: (Either String a)
115 -> (a -> Either String b)
117 combineEithers (Left s) _ = Left s
118 combineEithers (Right s) f = f s
120 ensureEitherList :: [Either String a] -> Either String [a]
121 ensureEitherList lst =
124 (Left x, _) -> Left x
125 (_, Left x) -> Left x -- should never happen
126 (Right e, Right a) -> Right (e:a)
130 eitherListHead :: Either String [a] -> Either String a
134 Right (x:_) -> Right x
135 Right [] -> Left "List empty"
137 readEitherString :: JSValue -> Either String String
140 JSString s -> Right $ fromJSString s
141 _ -> Left "Wrong JSON type"
143 parseEitherList :: (JSObject JSValue -> Either String String)
144 -> [JSObject JSValue]
145 -> Either String String
146 parseEitherList fn idata =
147 let ml = ensureEitherList $ map fn idata
148 in ml `combineEithers` (Right . unlines)
150 loadJSArray :: String -> Either String [JSObject JSValue]
151 loadJSArray s = resultToEither $ decodeStrict s
153 fromObj :: JSON a => String -> JSObject JSValue -> Either String a
155 case lookup k (fromJSObject o) of
156 Nothing -> Left $ printf "key '%s' not found" k
157 Just val -> resultToEither $ readJSON val
159 getStringElement :: String -> JSObject JSValue -> Either String String
160 getStringElement = fromObj
162 getIntElement :: String -> JSObject JSValue -> Either String Int
163 getIntElement = fromObj
165 getListElement :: String -> JSObject JSValue
166 -> Either String [JSValue]
167 getListElement = fromObj
169 concatEitherElems :: Either String String
170 -> Either String String
171 -> Either String String
172 concatEitherElems = applyEither2 (\x y -> x ++ "|" ++ y)
174 applyEither1 :: (a -> b) -> Either String a -> Either String b
178 Right y -> Right $ fn y
180 applyEither2 :: (a -> b -> c)
184 applyEither2 fn a b =
186 (Right x, Right y) -> Right $ fn x y
187 (Left x, _) -> Left x
188 (_, Left y) -> Left y