typespurescript

purescript data as array of all possible data inhabitants


I got the following data type:

data Icon = IconCircle | IconSquare | IconStar

I need an array of all possible Icons?:

allPossible :: Array Icon
allPossible = [IconCircle, IconSquare, IconStar]

Is there a shortcut to create this array? e.g when there are 20 (or a lot more) possible Icons?

When not:

Is it possible to create a type for allPossible that forces all possible Icons to be included?

My goal is to force that this array is never incomplete.


Solution

  • Yes, there is!

    You can derive Generic and then use GenericEnum in combination with GenericBottom to enumerate all constructors:

    data Icon = IconCircle | IconSquare | IconStar
    derive instance Generic Icon _
    
    allPossible :: Array Icon
    allPossible = unfoldr (\a -> Tuple a <$> genericSucc a) genericBottom
    

    And you can even make this completely generic, so it would work for any type, not just for Icon:

    allPossible :: forall a rep. 
      Generic a rep =>
      GenericEnum rep => 
      GenericBottom rep => 
      Array a
    allPossible = unfoldr (\a -> Tuple a <$> genericSucc a) genericBottom
    

    Of course, this will only work for types that are actually enums - i.e. every constructor is either parameterless or its parameters have instances of Enum. If the type is not an enum in this sense, this will fail to compile, complaining that it's impossible to construct a GenericEnum instance.