1

I am trying to write the function tails, which converts a string into a list of strings in the following way:

tails "abc" = ["abc", "bc", "c", ""]

Here is my implementation:

tails :: [Char] -> [[Char]]
tails (x:xs)
  | length (x:xs) == 0 = [""]
  | otherwise = (x:xs) : tails xs

As the title suggests, there are non-exhaustive patterns in this function. Unfortunately, I don't see how so.

I am new to Haskell... Any help would be appreciated!

Chris Martin
  • 30,334
  • 10
  • 78
  • 137
user376127
  • 35
  • 1
  • 4

2 Answers2

3

The pattern is non-exhaustive because it can't accept []. A list has form of either [] or a:as, where a is the leading element and as is the list of the trailing elements. So the pattern x:xs matches only if the list has a leading element. Fixing that gives:

tails :: [Char] -> [[Char]]
tails xs
    | length xs == 0 = [""]
    | otherwise = let (_:xs') = xs in xs : tails xs'

And then xs accepts the list regardless of its form. But this is inefficient due to length, and doesn't work for infinite lists.

This should fully work, which directly does pattern mathing:

tails :: [Char] -> [[Char]]
tails [] = [""]
tails xs@(_:xs') = xs : tails xs'
Dannyu NDos
  • 2,458
  • 13
  • 32
0

What about trying this or at least get some logic from it. It works well. It's got a helper function to convert the string into a list of separate characters, for example "abc" becomes ["a","b","c"]. It is just less complicated to process them like that and it becomes necessary to collect distinct strings in the result list. There are two functions in the function set and a third is warranted to call the primary function with one parameter. The primary function is on one line but uses guards.

ca = [[c] | c <- "abcdef"]
f (l1,ls) | null ls = l1++[[]] | True = f ( l1 ++ [concat ls], (tail ls))
f ([],ca)
["abcdef","bcdef","cdef","def","ef","f",""]

Edit 4/4/2018 I was wrong. The list parameter does not have to be made into a list before hand. By not doing so, the function becomes simpler by removing the concat function and changing the parameter list from tuple to individual removed lots or parentheses.

fs l1 ls = if null ls then l1++[""] else fs (l1++[ls]) (tail ls)

It is invoked differently, too.

fs [] "Hello!"

This, by itself, produced the right results.

Edit/add 4/11/2018

What keeps recurring (no pun) is dependence on tail when Haskell splits up input into head and tail with (x:xs) they are ready to use. Here is a basic recursive function that uses (x:xs) only for head and tail. I produces all tails of input list including null.

t [] = [""]; t (x:xs) = [x:xs] ++ t xs

And yet another that takes a list as the only parameter.

t ls = [drop n ls|n<-[0..length ls - 1]]
fp_mora
  • 718
  • 6
  • 11