4

i'm a beginner in Haskell and i'm trying to add an element at the end of a list.

I enter a list like [1,2,3,4] and a number 10. I want an output like this [1,2,3,4,10].

My code:

func a [] = a
func a (x:xs) = x : func a (x:xs)

But i'm getting that error:

Non type-variable argument in the constraint: Num [a]
(Use FlexibleContexts to permit this)
When checking that β€˜it’ has the inferred type
it :: forall a. (Num a, Num [a]) => [a]

Can anyone help with a explanation ?

Darius
  • 163
  • 1
  • 4
  • 14
  • 3
    Adding an item to the end of a list is a fine exercise, but usually you shouldn't do it in real Haskell programs. It's expensive, and indicates you are building your list in the wrong order. There is usually a better approach. – amalloy Mar 14 '17 at 23:41
  • It`s only an exercise for college :) – Darius Mar 15 '17 at 00:10

4 Answers4

10

How about a simple, non-recursive approach:

func num xs = xs ++ [num]

Or if you insist on recursion:

func num []     = [num]
func num (x:xs) = x : func num xs
Filip Toma
  • 101
  • 1
  • 2
8

You need to understand that what's happening with your definitions of the functions on the left side of the equals sign is "pattern matching".

With the following statement, you're basically saying

func a [] = a
...

I want first to accept an element of any type, i.e. a, as first parameter, and an empty list as the second parameter, i.e. []. If that's the case, you want to return a. The problem is, you want to return a list [a] (you will see later in this answer why).

With the second part of your function definition (this means that the first "pattern" has not matched against your inputs) you're saying: I accept an element of any type, i.e. a, and a non-empty list, i.e. (x:xs). (x:xs) is a way to say: ok, I have a list and x is the first element of that list. The rest of the list I call xs, which could be empty; in that case, your original list would be a list of size one, i.e. just [x].

...
func a (x:xs) = x : func a (x:xs)

What you return if the pattern is matched is

... = x : func a (x:xs)

which means that you're taking the first element of the list passed as the second parameter (i.e. x) and prepending it to the result of func a (x:xs).

Given this description of your problem, here's a possible solution:

func a [] = [a]
func a (x:xs) = x : func a xs

I would like to note two things here. In the first pattern, i.e func a [] = [a], I return a list, i.e. [a]. In the second pattern, I pass xs to func, i.e. func a xs. In both cases I return a list!

Why does this work? Lets have a look at an example. Let's say you call func like func 3 [1, 2]. Then this is what would happen.

Since [1, 2] is not an empty list, you do not match against the first pattern, so let's see the second; yes, we match against the second. Now we have that a = 3, x = 1 (the start of the list) and xs = [2]. So we then have 1 : func 3 [2]. So we recurse! We now have a = 3 (same as before), x = 2 and xs = [] (i.e. an empty list). So we proceed with the function body and we do 2 : func 3 []. Finally, func 3 [] matches against the first pattern, and you return [3]. But to what? Well, to 2 : [3], which returns to what? To 1 : 2 : [3].

nbro
  • 15,395
  • 32
  • 113
  • 196
3

Compare:

func a (x:xs) = x : func a (x:xs)
        --      ^^^^^^^^^^^^^^^^^  returns a list
func a [] = a
        --  ^  returns a non-list

Hence the type error. You probably want [a] or a : [] instead.

(Further, the recursive call is wrong, since you pass again the whole list x:xs in it. The list should get smaller else you will never reach the base case.)

chi
  • 111,837
  • 3
  • 133
  • 218
0

Try this:

padWith :: a -> [a] -> [a]
padWith k l = pad k l []
  where
    pad k [] a = (k:a)
    pad k (x:[]) a = pad x [] (k:a)
    pad k (x:y:zs) a = pad y (x:a) (pad k zs a)

Consider the case of an empty list: your new element will have been its only one. A singleton will have the new element at the end, so swap their positions in the function call, which means that y and x will have to be called in that order in lists of two elements or more. I think that it's a fun solution to have in mind in spite of simpler ones.

Marco_O
  • 99
  • 1
  • 8