3

When given a starting number and an increment, I want to be able to create a lists of lists in Haskell.

For example:

>listIncrease 5 3
[[5], [5,6], [5,6,7]]

I have tried using a recursive function but I haven't been able to get the function just right.

This is what I currently have:

listIncrease :: Int -> Int -> [[Int]]
listIncrease a 0 = []
listIncrease a b = [[a..a+b-1], (listIncrease a (b-2))]

I know this won't work because of the base case and because of the base case being incorrect, and the recursive step because you can't take an [[Int]] to be an [Int].

6 Answers 6

6

We can construct a range with:

[5 .. 7]

to create the final list we want:

Prelude> [5 .. 7]
[5,6,7]

We can then use inits :: [a] -> [[a]] to generate all prefixes:

Prelude Data.List> inits [5 .. 7]
[[],[5],[5,6],[5,6,7]]

We can use drop :: Int -> [a] -> [a] to omit the first element.

We can thus implement listIncrease as:

import Data.List(inits)

listIncrease :: (Num a, Enum a) => a -> a -> [[a]]
listIncrease lo n = drop 1 (inits [lo .. lo + n - 1])

For example:

Prelude Data.List> listIncrease 7 0
[]
Prelude Data.List> listIncrease 7 1
[[7]]
Prelude Data.List> listIncrease 7 2
[[7],[7,8]]
Prelude Data.List> listIncrease 7 3
[[7],[7,8],[7,8,9]]
Sign up to request clarification or add additional context in comments.

Comments

4

This will work:

listIncrease :: Int -> Int -> [[Int]]
listIncrease a b = [[a..i] | i <- [a..a+b-1]]

To understand why this works, consider evaluating the outer layers for your example of 5 and 3: [[5..i] | i <- [5..7]], [[5..i] | i <- [5,6,7]], and then [[5..5], [5..6], [5..7]].

2 Comments

Very nice answer. Covers all
This outputs your list: take 3 [ [5..n] | n <- [5..] ]
3

There is a standard library function just for this - inits. It returns all possible prefixes of a list, including the empty one:

> inits ['a', 'b', 'c']
[[], ['a'], ['a', 'b'], ['a', 'b', 'c']]

To get what you need, you just have to drop the first empty list, and you're done:

listIncrease a n = drop 1 $ inits [a .. (a+n-1)]

1 Comment

Lol, we wrote nearly exact the same answer at nearly the same time :)
2

Another option involving inits: create an infinite list of ranges, drop the first (empty) range, then take the next n elements:

listIncrease from n = take n (tail (inits [from..]))

This even has a nearly readable point-free version:

listIncrease = flip take . tail . inits . enumFrom

A quick explanation, showing the type of each step and an example using 5 and 3 as the arguments:

  • enumFrom :: Enum a => a -> [a] produces [5..]
  • inits . enumFrom :: Enum a => a -> [[a]] produces [[],[5],[5,6],[5,6,7],...]
  • tail . inits . enumFrom :: Enum a => a -> [[a]] produces [[5],[5,6],[5,6,7],...]
  • flip take . tail . inits . enumFrom :: Enum a => a -> Int -> [[a]] produces a function call (flip take) [[5],[5,6],[5,6,7],...] 3 == take 3 [[5],[5,6],[5,6,7],...] == [[5],[5,6],[5,6,7]]

Comments

1

I think this is the cleanest recursive implementation:

listIncrease :: Int -> Int -> [[Int]]
listIncrease a 0 = []
listIncrease a b = map (a:) $ [] : listIncrease (a + 1) (b - 1)

Comments

0

If you want to do it with traditional pattern matching you can try:

listIncrease :: Int -> Int -> [[Int]]
listIncrease a 0 = []
listIncrease a 1 = [[a]]
listIncrease a b = reverse $ ([a..a+b-1] : [a..a+b-2] : (listIncrease a (b-2)))

since the number could be odd and also you are making two steps each recursion, you should add the extra patter when the number its 1 , and reverse the list to has the desire order.

An optimized version using Sequence should be:

import Data.Sequence ((|>), empty, fromList)
import Data.Foldable (toList)

listIncrease :: Int -> Int -> [[Int]]
listIncrease a b = toList (fromSeq a b)

fromSeq a 0 = empty
fromSeq a 1 = fromList([[a]])
fromSeq a b = (fromSeq a (b-2)) |> [a..a+b-2] |> [a..a+b-1]

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.