Reputation: 21
Im trying to swap the first and last element of a list in haskell. I've tried pattern matchnig, expressions, functions, etc. This is my last attempt:
cambio xs = [ cabeza++([x]++cola)|x<-xs, cabeza <- init x, cola <- last x, drop 1 x, drop 0 ([init x])]
My compiler throws the next error:
Couldn't match expected type `Bool' with actual type `[a0]'
In the return type of a call of `drop'
In the expression: drop 1 x
In a stmt of a list comprehension: drop 1 x
Can anyone help me? I've tried to do this for 2 days
Upvotes: 1
Views: 2902
Reputation: 2770
This is a fairly straightforward thing to do, especially with the standard list functions:
swapfl [] = []
swapfl [x] = [x]
swapfl (x:xs) = (last xs : init xs) ++ [x]
Or without them (although this is less readable and usually not done, and not recommended):
swapfl' [] = []
swapfl' [x] = [x]
swapfl' (x:xs) = let (f, g) = sw x xs in f:g
where sw k [y] = (y, [k])
sw k (y:ys) = let (n, m) = sw k ys in (n, y:m)
Or one of many other ways.
I hope that helps ... I know I didn't do much explaining, but frankly, it's hard to tell exactly what you were having trouble with as far as this function is concerned, seeing as you also seem to completely misunderstand list comprehensions. I think it might be most beneficial if I explain those instead?
And why this cant be solved with a list comprehension? I tough they were like functions but with a different form
Not really. List comprehensions are useful for easily defining lists, and they're very closely related to set-builder notation in mathematics. That would not be useful for this particular application, because, while they're very good at modifying the elements of a list, comprehensions are not very good at reordering lists.
In a comprehension, you have three parts: the definition of an element in the list, one or more input lists, and zero or more predicates:
[ definition | x <- input1, y <- input2, predicate1, predicate2 ]
The definition describes a single element of the list we're making, in terms of the variables the arrows in the inputs are pointing at (x and y in this case). Each input has a list on the right of the arrow, and a variable on the left. Each element in the list we're making is built by extracting each combination of elements from the input lists into those variables, and evaluating the definition part using those values. For example:
[ x + y | x <- [1, 3], y <- [2, 4] ]
This generates:
[1 + 2, 1 + 4, 3 + 2, 3 + 4] == [3, 5, 5, 7]
Also, you can include predicates, which are like filters. Each predicate is a boolean expression defined in terms of the input elements, and each is evaluated whenever a new list element is. If any of the predicates come out to be false, those elements aren't put in the list we're making.
Let's look at your code:
cambio xs = [ cabeza++([x]++cola) | x<-xs, cabeza <- init x, cola <- last x,
drop 1 x, drop 0 ([init x])]
The inputs for this comprehension are x <- xs
, cabeza <- init x
, and cola <- last x
. The first one means that every element in xs
is going to be used to define elements for the new list, and each element is going to be named x
. The other two don't make any sense, because init
and last
are type [a] -> a
, but are on the right side of the arrow and so must be lists, and x
must be an element of a list because it's on the left side of its arrow, so in order for this to even compile, xs would have to be type [[[a]]]
, which I'm sure is not what you want.
The predicates you used are drop 1 x
and drop 0 [init x]
. I kind of understand what you were trying to do with the first one, dropping the first element of the list, but that wouldn't work because x
is just an element of the list, not the list itself. In the second one, drop 0
means "remove zero elements from the beginning of the following list", which would do absolutely nothing. In either case, putting something like that in a predicate wouldn't work because the predicate needs to be a boolean value, which is why you got the compiler error. Here's an example:
pos xs = [ x | x <- xs, x >= 0 ]
This function takes a list of numbers, removes all the negative numbers, and returns the result. The predicate is the x >= 0
, which is a boolean expression. If the expression evaluates to false, the element being evaluated is filtered out of the resulting list.
The element definition you used is cabeza ++ [x] ++ cola
. This means "Each element in the resulting list is itself a list, made up of all elements in the list cabeza
, followed by a single element that contains x
, followed by all elements in the list cola
", which seems like the opposite of what you were going for. Remember that the part before the pipe character defines a single element, not the list itself. Also, note that putting square brackets around a variable creates a new list that contains that variable, and only that variable. If you say y = [x]
, this means that y contains a single element x, and doesn't say anything about whether x is a list or not.
I hope that helps clear some things up.
Upvotes: 2
Reputation: 3093
I think that lists aren't the best data structure for doing this, but here it goes:
swap list = last list : (init . tail $ list) ++ [head list]
This is going to require traversing the list and will be slow on long lists. This is the nature of linked lists.
Updated with base cases from question asker:
swap [] = []
swap [a] = [a]
swap list = last list : (init . tail $ list) ++ [head list]
Upvotes: 2
Reputation: 36339
Here are a few hints:
In all other cases the length of the input list will be >= 2. The list you want is
[z] ++ xs ++ [a]
where z is the last element, a the first element of the input list and xs the middle part of the input.
Now tell me (or yourself), how long will xs be, if the length of the input string was k?
Upvotes: 4