0

Short Question (edited):

Is it possible to define a function's type signature so that it accepts nested types with arbitrary depth? I am looking for the behaviour of type synonyms (NOT newtype) but identifying nested/recursive types.

For example a function defined as f :: NestedList a -> b should be able to be called with [a], [[a]], [[[a]]]... and so on.

Long Question (original):

Since it is impossible to use type synonyms in Haskell with recursive types, is there a solution for the following problem?

I need a synonym like NestedList a that would identify [a], [[a]], [[[a]]]... and so on, in function type definitions. An example of function needed to be implemented is:

   flatten :: NestedList a -> [a]

This post shows a solution for flatten using the MultiParamTypeClasses language extension, but it does not particularly solve my problem. I need to define functions outside of a class.

EDIT:

flatten is just an example for a function definition, I am not interested in the function as such. I need a mechanism to define a function with NestedList a and call it with a parameter like [[a]] or [[[a]]], without the need of an additional type constructor, get methods, etc. As suggested in the title, I need something that behaves like a type synonym on nested lists, mainly for giving type signatures for functions that work on [...[a]...] while making sure the base type is a.

According to Haskell's strong-typed system this is impossible and this post sheds some light on the reasons why. I am just asking if there is a macro/synonym like mechanism or workaround, or a language extension that permits me to do that.

Community
  • 1
  • 1
Iedu
  • 117
  • 8

1 Answers1

6

Are you looking for something like this?

data NestedList a = List [NestedList a] | Element a

flatten :: NestedList a -> [a]
flatten (Element x) = [x]
flatten (List xs)   = concatMap flatten xs

EDIT

As user2407038 has suggested, if you are interested in using the Foldable (include {-# LANGUAGE DeriveFoldable #-} at the top of your file and import Data.Foldable) GHC extension, you can just do this

data NestedList a = List [NestedList a] | Element a deriving (Foldable)

And then there is a function called toList already defined in Foldable which will produce the same output as flatten from above.

EDIT 2

Here is something else of interest concerning the updated question. Ideally, it would be nice to be able to define an instance of Foldable with

instance (Foldable t, Functor t, Foldable t') => Foldable (t . t')

where (t . t') a is a type synonym for t (t' a) (a sort of type level composition). This obviously doesn't work, and I'm inclined to think there is a logical explanation as to why introducing this would break Haskell in some fundamental way, but I can't think of it. However, there is a package called Control.Compose which defines something almost like that (except for the fact we would like a type synonym as opposed to a newtype).

newtype (g :. f) a = O { unO :: g (f a) }

This lets us write the following:

toList $ (O) [[1,2,3,4],[4,5,6]]
toList $ (O . O) [[[1],[2,3,4]],[[4],[5,6]]]
toList $ (O . O . O) [[[[1]],[[2,3],[4]]],[[[4]],[[5,6]]]]

Which is also of interest.

Alec
  • 31,829
  • 7
  • 67
  • 114
  • Or just `data NestedList a = List [NestedList a] | Element a deriving Foldable`. – user2407038 Jun 23 '15 at 02:12
  • Indeed, your solution does work with `flatten`, but this is not what I am trying to achieve. I guess I was not very specific, and I will edit my question. The problem is that I cannot use `[[[Int]]]` and `NestedList Int` interchangeably, i.e. call the function with `[[[Int]]]`. This is why I would like something that works like type synonyms. – Iedu Jun 23 '15 at 06:43
  • 1
    @GeorgeUngureanu I see. I don't think you will find type synonym `Datalist a` that will work for `[a]`, `[[a]]`, etc. since that would mean that `[a] = Datalist a = [[a]]` yet this is clearly untrue. – Alec Jun 23 '15 at 06:58
  • @Alec: Absolutely! And Haskell does not permit that, indeed. But a function implemented in an applicative manner works perfectly with `[a]`, `[[a]]`, etc. I just need to give that function a type signature (while still making sure that the base type is `a`) – Iedu Jun 23 '15 at 07:47