0
votes

I want to create a type class for various types of "columns of stuff", so something like this:

class Column c where
     at :: c a -> Int -> a

data ListColumn a = ListColumn {
     lcContent :: [a]
}

instance Column ListColumn where
  at c i = lcContent c !! i

Now I want to derive one column from another. Say I have a column of customers, and I want to derive a column of customer names from that. So I wrote:

data DerivedColumn a b c = DerivedColumn {
    dcBase   :: c a, 
    dcDerive :: a -> b
}

a being the customer, b the customer name in the example above. Now I thought I could write something like this:

instance Column (DerivedColumn a b) where
    at c i = dcDerive c $ at (dcBase c) i

But ghc does not seem to like it (Column should have kind * -> *, but DerivedColumn a b has kind (* -> *) -> *). Can someone please point in the right direction...?

1
It’s a little bit unclear to me what exactly you want, but it looks like maybe you need to shuffle the type variables from DerivedColumn to have the container type, a, last? So the definition should be data DerivedColumn c b a = ...? The Column typeclass expects a type that it can apply a container type to in order to get a concrete type.Alexis King
Yes, that makes sense, thank you!martingw

1 Answers

2
votes

I think what you want instead is this:

data DerivedColumn c a b = DerivedColumn {
    dcBase   :: c a, 
    dcDerive :: a -> b
}

instance Column c => Column (DerivedColumn c a) where
    at dc i = dcDerive $ at (dcBase dc) i

To expand a bit, if you look at your Column class, you'll see that c has kind * -> *, and the a in c a is the type of the values that c contains. I assume that the value of the columns that DerivedColumn a b c contains should have type b, so it should really be the last value you pass to the type constructor for you to define an instance of Column.