Last active
December 17, 2015 17:49
-
-
Save dtchepak/5648603 to your computer and use it in GitHub Desktop.
Attempt at Survey Csv exercise in Haskell. https://gist.github.com/dtchepak/5640717
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Data.Char | |
import Data.List | |
import Data.Maybe | |
import Data.Monoid | |
import Data.Traversable (traverse) | |
data ProgrammingLanguage | |
= CSharp | |
| FSharp | |
| Haskell | |
| Ruby | |
| JavaScript | |
deriving (Eq, Show) | |
data SurveyResponse = | |
Resp { site :: String | |
, results :: [(ProgrammingLanguage, Int)] | |
} | |
type Col = (String, SurveyResponse -> String) | |
reportColumns :: [Col] | |
reportColumns = | |
let lower = fmap toLower | |
lookupCol :: ProgrammingLanguage -> Col | |
lookupCol l = ( lower (show l) | |
, show . fromMaybe 0 . lookup l . results) | |
in | |
[ ("site", site) | |
, lookupCol CSharp | |
, lookupCol FSharp | |
, lookupCol Haskell | |
, lookupCol Ruby | |
, lookupCol JavaScript | |
] | |
surveyToCsv :: [SurveyResponse] -> String | |
surveyToCsv = | |
let joinOn = intercalate | |
toCsv = joinOn "," | |
headers = toCsv $ fmap fst reportColumns | |
values = toCsv . traverse snd reportColumns | |
in | |
joinOn "\n" . (headers:) . fmap values | |
sample = | |
[ Resp "site1" [(CSharp, 3), (FSharp, 1), (Haskell, 0)] | |
, Resp "site2" [(CSharp, 3), (Ruby, 5)] | |
, Resp "site3" [(Ruby, 7), (JavaScript, 4)] | |
] | |
main = putStrLn $ surveyToCsv sample |
Thanks @bens, I had trouble getting lookupCol
pointfree (was trying to use (&&&)
). I'll give it another go.
No problem @dtchepak. I have to take back the (&&&)
comment, it's not as straightforward as it seemed at first. It can be done and I'm happy to post my result if you want, but it's much less readable than what you have.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I'd make a
type Csv = [[String]]
andrenderCsv :: Csv -> String
function. ThensurveyToCsv :: [SurveyResponse] -> Csv
andmain = putStrLn . renderCsv $ surveyToCsv sample
. To me, converting your data to a generic but slightly structured form and transforming that to an unstructured string ought to be separated.I wouldn't bother defining
lower
because its definition is very simple and only used once.joinOn "\n"
can just beData.List.unlines
, and I thinkconcat . intersperse x
isData.List.intercalate x
.If you wanted you could make
lookupCol
point-free with aflip
andControl.Arrow.(&&&)
.