Variadic functions.... What about Variadic Types?

You can a little bit get around this with GADS. GADTs let you discover types by pattern matching. For example:

import Text.Read
import Data.Maybe

data Column a where
    ColInt :: {header :: String, ints :: [Int]} -> Column ()
ColDate :: {header :: String, dates :: [Date]} -> Column ()
    ColStr :: {header :: String, strs :: [String]} -> Column ()

readCol (h:(v:vs))
    | Just v' <- readMaybe v :: Maybe Int = ColInt h (v': map read vs)
    | Just v' <- readMaybe v :: Maybe Date = ColDate h (v': map read vs)
    | otherwise = ColStr h vs

This is oversimplified for example purposes. It assumes that each column can be just parsed via the Haskell Read class, and that the CSV does not mix types in columns.

However, you only need to write it once to cover the types you're interested in using. That's the point of the last line of unchecked Strings - everything you don't care about is just String data.

 Prelude Text.Read

readCol (words "ho ho ho") ColStr {header = "ho", strs = ["ho","ho"]}

Prelude Text.Read

readCol (words "ho 1 2") ColInt {header = "ho", ints = [1,2]}

The reason you have to do it this way, is because types can't really split. That is, you can't currently easily have a type String -> {Int, Bool} where the output is one of Int or Bool, that's one possible type in, and one of two possible types out and which is unknown at compile time. On the other hand String -> Column () has 1 type in and 1 type out. Note, this code will let you try to get the ints from a ColStr which doesn't have any, and just error out. Since you just want to play with the data, I'm assuming this won't be to big an issue. Yes, the code is repetitive, but that also means you can copy/paste most of it and set it up quickly. There are other options that will eliminate this boilerplate, but I would not recommend them for a beginner - I set this up so it should be easy to see what I'm doing, and how you can extend it.

/r/haskell Thread