How can I apply a function to all elements of a heterogeneous list when they are all instances of the same class?

Viewed 87
Prelude> import Data.HList
Prelude Data.HList> let myList = False .*. 'c' .*. HNil
Prelude Data.HList> myList
H[False,'c']
Prelude Data.HList> :t myList
myList :: HList '[Bool, Char]

Now,

Prelude Data.HList> hMap show myList

    <interactive>:5:1: error:
        * Couldn't match type `Bool' with `Char'
            arising from a use of `hMap'
        * In the expression: hMap show myList
          In an equation for `it': it = hMap show myList

I would expect to have H["False","'c'"] of type H[String,String]

I understand that the show function is indeed not the same instance for the type Bool and the type Char , but I don't get the point of this HList if such operation is impossible.

How to operate generically with function part of the instances that those types share instanciation ?

1 Answers

As others have said in comments, there are alternatives to HList that might be a lot easier to use.

Anyway, I think you're supposed to write:

hMap HShow myList

The way the HList package works, all operations on HLists are lifted to the type class level, and higher-order functions like hMap and hFoldr don't work with "normal" worker functions, but need them lifted to the type class level as well.

Here, HShow is defined using a proxy data type and an instance for the ApplyAB class:

data HShow = HShow
instance (String ~ string, Show a) => ApplyAB HShow a string where
    applyAB _ x = show x

If you have your own function:

add5 :: (Num a) => a -> a
add5 = (+5)

you need to define a similar data type and instance for it:

data HAdd5 = HAdd5
instance (Num a, a ~ b) => ApplyAB HAdd5 a b where
  applyAB _ x = add5 x

and then:

> let myList = (10.1 :: Double) .*. (6 :: Int) .*. HNil
> print $ hMap HAdd5 myList
H[15.1,11]

Writing these instances can be a little tricky. If the above instance had been written in the more natural form:

instance (Num a) => ApplyAB HAdd5 a a where
  applyAB _ x = add5 x

then type inference wouldn't work very well.

There doesn't seem to be a lot of documentation on HList, and the official paper doesn't look like it would make a very good general use tutorial. Maybe this blog post will help?

Related