4
\$\begingroup\$

I wrote code that parses a table header string in order to obtain two string tags, one for variable name (like GDP) and another for unit of measurement (like bln_rub). The tags collectively make a unique identifier for the table data.

Perhaps something can be done better/shorter/more easily readable?

import Data.List (isInfixOf)
type Label = Maybe String
data Variable = Variable
 { name :: Label,
 unit :: Label
 } deriving (Show, Eq)
makeVariable :: String -> String -> Variable 
makeVariable name unit = Variable (Just name) (Just unit) 
isDefined:: Variable -> Bool
isDefined var = (name var /= Nothing) && (unit var /= Nothing) 
isIdentical:: Variable -> String -> String -> Bool
isIdentical var name unit = (makeVariable name unit) == var 
-- Map allows a readable view of tuple-like 
-- associative structure. 
data Map = Map 
 { label :: String,
 texts :: [String] -- note: can use non-empty List 
 } deriving (Show)
nameMaps = [
 Map "GDP" ["Gross domestic product"]
 , Map "INDPRO" ["Industrial production"]
 ]
unitMaps = [
 Map "bln_rub" ["bln rub", "billion ruble"]
 , Map "rog" ["% change to previous period"] -- rate of growth
 ] 
-- COMMENT: code below converts nameMaps and unitMaps
-- to list of tuples which are used for searching a header
asTuples :: Map -> [(String, String)] 
asTuples (Map label texts) = [(text, label) | text <- texts] 
findAllKeys :: [(String, String)] -> String -> [String]
findAllKeys mapper header = [key | tup@(text, key) <- mapper, 
 text `isInfixOf` header]
getLabel :: [Map] -> String -> Label
getLabel maps' header = case findAllKeys (flatten' maps') header of 
 [] -> Nothing
 (x:_) -> Just x
 where flatten' = concatMap asTuples
getName = getLabel nameMaps
getUnit = getLabel unitMaps
parseHeader text = Variable (getName text) (getUnit text)
x = parseHeader "Gross domestic product, bln rub"
flag = (isDefined x) && (isIdentical x "GDP" "bln_rub")
raise x = error ("Something wrong with: " ++ show x) 
main = do
 if flag then putStrLn $ show x else
 raise x 
 return ()
Jamal
35.2k13 gold badges134 silver badges238 bronze badges
asked Oct 3, 2018 at 18:21
\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

Perhaps something can be done shorter

A trick that I often use to avoid creating "filled" objects is simply matching on Just:

isIdentical:: Variable -> String -> String -> Bool
isIdentical (Variable (Just n) (Just u)) n' u' = n == n' && u == u'
isIdentical _ _ _ = False

You can even do the actual check inside the pattern guard:

(Variable (Just n) (Just u)) n' u' | n == n' && u == u' = True

But that seems like an overkill.

Not saying that this change is particularly warranted in this specific case, but it's a nice tool to have, I think.

answered Oct 3, 2018 at 20:47
\$\endgroup\$
2
  • \$\begingroup\$ I think it is good reminder of pattern matching and avoiding duplicate work that is happening after one creates an object and then equates it to something. \$\endgroup\$ Commented Oct 3, 2018 at 20:53
  • \$\begingroup\$ A guard also seems a bit more readable. Thank you for the suggestions! \$\endgroup\$ Commented Oct 4, 2018 at 5:22

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.