It's been over a year now but no correct answers were given so here's my take on it.
Let's start with the type signature:
tails' :: [a] -> [[a]]
This sugests that tails'
should return a list-of-lists. The terminal case you syggested is just an empty list. Change it to:
tails' [] = [[]]
Now, the general case. Let's assume that our tails'
works the way we want it to:
tails' [] -> [[]]
tails' [1] -> [[1], []]
tails' [2,1] -> [[2,1], [1], []]
tails' [3,2,1] -> [[3,2,1], [2,1], [1], []]
As we can see, we want to include the original list and the empty list. This means that given an input list xs
, we want to concatenate xs
onto something else.
But what's that something else? Let's do a bit of pseudo-haskell math:
let A = tails' [3,2,1] = [[3,2,1], [2,1], [1], []]
let B = tails' [2,1] = [[2,1], [1], []]
=> A = [[3,2,1], B] -- (1)
tail [3,2,1] == [2,1]
=> B = tails' (tail [3,2,1]) -- (2)
By (1) and (2)
A = [[3,2,1], tails' (tail [3,2,1])]
=> tails' [3,2,1] = [[3,2,1], tails' (tail [3,2,1])] -- (3)
By replacing [3,2,1] in (3) with xs
tails' xs = [xs, tails' (tail xs)]
Translating all this into Haskell gives us:
tails' :: [a] -> [[a]]
tails' [] = [[]]
tails' xs = xs : (tails' $ tail xs)
main = do
print $ tails' [1,2,3]
-- [[1,2,3],[2,3],[3],[]]