Skip to content

Instantly share code, notes, and snippets.

@dtchepak
Last active December 17, 2015 17:49
Show Gist options
  • Save dtchepak/5648603 to your computer and use it in GitHub Desktop.
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
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
@bens
Copy link

bens commented May 25, 2013

I'd make a type Csv = [[String]] and renderCsv :: Csv -> String function. Then surveyToCsv :: [SurveyResponse] -> Csv and main = 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 be Data.List.unlines, and I think concat . intersperse x is Data.List.intercalate x.

If you wanted you could make lookupCol point-free with a flip and Control.Arrow.(&&&).

@dtchepak
Copy link
Author

Thanks @bens, I had trouble getting lookupCol pointfree (was trying to use (&&&)). I'll give it another go.

@bens
Copy link

bens commented May 26, 2013

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