Possible outcomes

Hi, new to Haskell!

data Fruits = Apple | Banana | Pear | Cherry deriving (Eq, Show)
data Ncolour = Numeric Int | Red | Yellow | Green | Red deriving (Eq, Show)

The numeric int should be from 1 to 10.

I want to write a function that returns a list of all possible outcomes of the data shown above and I don’t know how to do it? I have tried many times but still couldn’t figure it out…


What is an outcome? What have you tried?

Do you want the cartesian product between Fruits and Ncolour? What’s the purpose of Numeric Int here?

For example:
[(Numeric 2) Apple] [(Numeric 2) Banana]
[(Numeric 2) Pear] [(Numeric 2) Cherry]
[Red Apple] and so on… All possible combinations.

Okay. You can pair it manually through recursion if you prefer. But you could also use list comprehensions, or some lifting.

In any of the approaches, you can pair them together with tuples, rather than a list since it seems like you only want a fixed amount of elements with varying types Fruit and Ncolour. Normally, lists in Haskell are homogeneous so you can’t have an element that’s a Fruit, and another element that’s an Ncolour.

i.e You can’t (normally) do [Numeric 2, Apple], but you can do (Numeric 2, Apple).

List comprehension

List comprehensions gets you the cartesian product, which is what you’re looking for. (You can read more about list comprehensions here).

fruitColorPairsLC :: [(Ncolour, Fruit)]
fruitColorPairsLC =
  [(nColour, fruit) | 
         nColour <- [Numeric 2, Red, Yellow, Green],
         fruit <- [Apple, Banana, Pear, Cherry] ]


If you want to explore the concept of functors and applicatives, using both can also give you the same result. This one is really cool, but do this when you’re more comfortable with recursion and whatnot.

fruitColorPairsLift :: [(Fruit, Ncolour)]
fruitColorPairsLift = 
  liftA2 (,) 
    [Numeric 2, Red, Yellow, Green] 
    [Apple, Banana, Pear, Cherry]

or this is equivalent to

fruitColorPairsLift :: [(Ncolour, Fruit)]
fruitColorPairsLift = 
  (,) <$> [Numeric 2, Red, Yellow, Green] <*> [Apple, Banana, Pear, Cherry]

This lifts the binary function (,) to work with a list context. It’s a lot to get into so some helpful resources, when you choose to study these type classes, are:

  1. https://github.com/kowainik/learn4haskell
  2. https://github.com/system-f/fp-course
  3. https://haskellbook.com/

Either approach gives you

[(Numeric 2,Apple),(Numeric 2,Banana),(Numeric 2,Pear),(Numeric 2,Cherry),(Red,Apple),(Red,Banana),(Red,Pear),(Red,Cherry),(Yellow,Apple),(Yellow,Banana),(Yellow,Pear),(Yellow,Cherry),(Green,Apple),(Green,Banana),(Green,Pear),(Green,Cherry)]

But if i want that the integer varies from 1 to 10 how do I do it?

I did this and it works… But i feel like it can be done in another more easier way.

data Out = Out Ncolour Fruits deriving (Eq, Show)

ncolour :: Out -> Ncolour
ncolour (Out n _) = n

fruits :: Out -> Fruits
fruits (Out _ f) = f

type shoow = [Out]

combinations:: Shoow
combinations = [Out n f | n <- [Numeric 2, Numeric 3,Numeric 4,Numeric 5,Numeric 6,Numeric 7,Numeric 8,Numeric 9, Numeric 10, Red, Yellow, Green, Red], f <- [Apple, Banana, Pear, Cherry]]

You can generate a list and append the rest of the colors!

fruitColorPairsLC =
  [(colour, fruit) |
    colour <- nColours ++ [Red, Yellow, Green],
    fruit <- [Apple, Banana, Pear, Cherry] ]
  where nColours =
          [Numeric n | n <- [1..10]]

There is a cost to appending lists though since it traverses the entire first list to append the second. But for 1-10 it should be fine.

1 Like
data Fruit = Apple | Banana | Pear | Cherry deriving (Eq, Show, Enum)
data Ncolour = Numeric Int | Red | Yellow | Green deriving (Eq, Show)

// A smart constructor for all valid colors
allColours :: [Ncolour]
allColours = map Numeric [1..10] ++ [Red, Yellow, Green]

allFruits :: [Fruit]
allFruits = [Apple .. Cherry]

allCombinations :: [(Fruit, Ncolour)]
allCombinations = (,) <$> allFruits <*> allColours
1 Like