Why doesn't this definition cover all pattern cases?
Asked Answered
G

3

5

So I'm trying to triplize an element, i.e. making 2 other copies of the element.

So I've written this:

triplize :: [a] -> [a]
triplize [x] = concatMap (replicate 3) [x]

But I've been getting this error:

Non-exhaustive patterns in function triplize

I'm new to Haskell, so any pointers are appreciated!

Grotto answered 11/9, 2015 at 21:52 Comment(3)
What about when the list is empty. You don't catch that case?Chaker
Dont need to account for that :)Grotto
@NeedHelp Yes you do. triplize [] = [], by your definition. Incomplete functions are considered harmful.Diphtheria
A
7

When you write

triplize [x]

You are saying that the argument must match the pattern [x]. This pattern represents a list with a single value, which will be assigned to the name x. Note that the list will not be assigned to the name x, only the single value in that list. If you tried calling your function with the list [] or [1, 2], it would cause an error because you haven't told your function what to do with those inputs.

What you probably want is

triplize x = concatMap (replicate 3) x

Here your pattern is just x, which matches any list, from the empty list to an infinite list. Notice that the patterns in your function definition match the way you make the values themselves. In Haskell you can pattern match on constructors, and lists can be constructed with square brackets and commas, or they can be constructed using the : operator, so [1, 2, 3] == (1:2:3:[]). In fact, the : operator is how Haskell represents lists internally.

An example that uses more pattern matches:

sumSuccessive :: [Int] -> [Int]
sumSuccessive [] = []      -- Empty list
sumSuccessive [x] = [x]    -- Singleton list (only one value)
sumSuccessive (x:y:rest) = x + y : sumSuccessive rest
    -- Match a list with at least two elements `x` and `y`,
    -- with the rest of the list assigned to the name `rest`

This example function would take the list [1, 2, 3, 4] and return the list [3, 7] ([1 + 2, 3 + 4]).

Arkhangelsk answered 11/9, 2015 at 22:2 Comment(1)
A common idiom for naming parameters like that is to use xs or similar for list names. E.g. triplize xs = concatMap (replicate 3) xsMacrocosm
R
3

You can define triplize as:

triplize :: [a] -> [a]
triplize x = concatMap (replicate 3) x

But there's even no need to write x:

triplize :: [a] -> [a]
triplize = concatMap (replicate 3)

The original code will work only on lists with one element:

> triplize [1]
[1, 1, 1]
> triplize []
*** Exception: Non-exhaustive patterns in function triplize
> triplize [0, 1]
*** Exception: Non-exhaustive patterns in function triplize
Roadability answered 11/9, 2015 at 22:2 Comment(0)
J
1

[x] matches a list of exactly one element. If you want to match any list, just remove [ and ]:

triplize x = concatMap (replicate 3) x

This would turn ["a", "b", "c"] into ["a", "a", "a", "b", "b", "b", "c", "c", "c"].

On the other hand, if you want to take one element and return a list (containing 3 of that element), then your code should be

triplize :: a -> [a]
triplize x = replicate 3 x
Jemadar answered 11/9, 2015 at 22:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.