1 {-| Utility functions -}
3 module Ganeti.HTools.Utils
38 import Text.Printf (printf)
42 -- | To be used only for debugging, breaks referential integrity.
43 debug :: Show a => a -> a
44 debug x = trace (show x) x
46 -- | Check if the given argument is Left something
47 isLeft :: Either a b -> Bool
53 fromLeft :: Either a b -> a
54 fromLeft = either (\x -> x) (\_ -> undefined)
56 fromRight :: Either a b -> b
57 fromRight = either (\_ -> undefined) id
59 -- | Comma-join a string list.
60 commaJoin :: [String] -> String
61 commaJoin = intercalate ","
63 -- | Split a string on a separator and return an array.
64 sepSplit :: Char -> String -> [String]
66 | x == "" && xs == [] = []
69 | otherwise = x:(sepSplit sep ys)
70 where (x, xs) = break (== sep) s
73 -- | Partial application of sepSplit to @'.'@
74 commaSplit :: String -> [String]
75 commaSplit = sepSplit ','
77 -- | Swap a list of @(a, b)@ into @(b, a)@
78 swapPairs :: [(a, b)] -> [(b, a)]
79 swapPairs = map (\ (a, b) -> (b, a))
81 -- Simple and slow statistical functions, please replace with better versions
83 -- | Mean value of a list.
84 meanValue :: Floating a => [a] -> a
85 meanValue lst = (sum lst) / (fromIntegral $ length lst)
87 -- | Standard deviation.
88 stdDev :: Floating a => [a] -> a
90 let mv = meanValue lst
91 square = (^ (2::Int)) -- silences "defaulting the constraint..."
92 av = sum $ map square $ map (\e -> e - mv) lst
93 bv = sqrt (av / (fromIntegral $ length lst))
96 -- | Coefficient of variation.
97 varianceCoeff :: Floating a => [a] -> a
98 varianceCoeff lst = (stdDev lst) / (fromIntegral $ length lst)
100 -- | Get a Right result or print the error and exit
101 readData :: (String -> IO (Either String String)) -> String -> IO String
102 readData fn host = do
106 putStrLn $ fromLeft nd
107 exitWith $ ExitFailure 1
108 return $ fromRight nd
110 {-- Our cheap monad-like stuff.
112 Thi is needed since Either e a is already a monad instance somewhere
113 in the standard libraries (Control.Monad.Error) and we don't need that
117 combineEithers :: (Either String a)
118 -> (a -> Either String b)
120 combineEithers (Left s) _ = Left s
121 combineEithers (Right s) f = f s
123 ensureEitherList :: [Either String a] -> Either String [a]
124 ensureEitherList lst =
127 (Left x, _) -> Left x
128 (_, Left x) -> Left x -- should never happen
129 (Right e, Right a) -> Right (e:a)
133 eitherListHead :: Either String [a] -> Either String a
137 Right (x:_) -> Right x
138 Right [] -> Left "List empty"
140 readEitherString :: JSValue -> Either String String
143 JSString s -> Right $ fromJSString s
144 _ -> Left "Wrong JSON type"
146 parseEitherList :: (JSObject JSValue -> Either String String)
147 -> [JSObject JSValue]
148 -> Either String String
149 parseEitherList fn idata =
150 let ml = ensureEitherList $ map fn idata
151 in ml `combineEithers` (Right . unlines)
153 loadJSArray :: String -> Either String [JSObject JSValue]
154 loadJSArray s = resultToEither $ decodeStrict s
156 fromObj :: JSON a => String -> JSObject JSValue -> Either String a
158 case lookup k (fromJSObject o) of
159 Nothing -> Left $ printf "key '%s' not found" k
160 Just val -> resultToEither $ readJSON val
162 getStringElement :: String -> JSObject JSValue -> Either String String
163 getStringElement = fromObj
165 getIntElement :: String -> JSObject JSValue -> Either String Int
166 getIntElement = fromObj
168 getListElement :: String -> JSObject JSValue
169 -> Either String [JSValue]
170 getListElement = fromObj
172 getObjectElement :: String -> JSObject JSValue
173 -> Either String (JSObject JSValue)
174 getObjectElement = fromObj
176 asJSObject :: JSValue -> Either String (JSObject JSValue)
177 asJSObject (JSObject a) = Right a
178 asJSObject _ = Left "not an object"
180 asObjectList :: [JSValue] -> Either String [JSObject JSValue]
182 ensureEitherList . map asJSObject
184 concatEitherElems :: Either String String
185 -> Either String String
186 -> Either String String
187 concatEitherElems = applyEither2 (\x y -> x ++ "|" ++ y)
189 applyEither1 :: (a -> b) -> Either String a -> Either String b
193 Right y -> Right $ fn y
195 applyEither2 :: (a -> b -> c)
199 applyEither2 fn a b =
201 (Right x, Right y) -> Right $ fn x y
202 (Left x, _) -> Left x
203 (_, Left y) -> Left y