nobody
nobody

Reputation: 2759

Haskell pattern matching the first, middle section, and last

So I wanted to do a simple string reverse function in Haskell

swapReverse :: String => String  
swapReverse [x] = [x]
swapReverse [x,y] = [y,x]
swapReverse (x:xs:l) =         -- pattern match fails here 
  let last = [l]
      middle = xs
      first = [x]
  in  last ++ swapReverse middle ++ first

So is there a way to define a pattern structure in haskell that has first and last element, and all the elements in the middle ?

Upvotes: 8

Views: 4312

Answers (4)

Landei
Landei

Reputation: 54584

A working version:

swapReverse :: String -> String  
swapReverse (x:xs) = [last xs] ++ swapReverse (init xs) ++ [x]
swapReverse xs = xs

Note that this implementation is performance-wise a disaster. Implementations using a fold and/or accumulators are much more efficient.

Upvotes: 0

user721010
user721010

Reputation:

Try this code:

last1 (x:xs:l) = (x,xs,l)

l doesn't get you the last element in a list, it get's you the rest of the list besides the first two variables, which are assigned the first two elements in a list.

When you write a pattern match for a list, the first variable is assigned the first element, and so on, until the program get's to the last variable, where everything that is left is assigned to it. There is nothing special about adding an s after an x, a variable named y would do the same thing.

If you want to get the last element of a list, you need to create a pattern similar to (x:xs), and use recursion on xs and apply that pattern until you get down to one list element, which is the last element. However, I would recommend reading Adam Bergmark's answer for a better way to reverse a list that does not involve finding the first and last elements of a list.

Upvotes: 2

Luis Casillas
Luis Casillas

Reputation: 30227

No, you cannot. Why? Because pattern matches match values and their subparts, but the "middle" of a list isn't a subpart of the list. The list [1, 2, 3, 4] is 1:(2:(3:(4:[]))), in terms of its structure. So you want to match first to 1 and last to 4, which are both subparts of the list, and thus not disqualified. But the middle that you want would be 2:(3:[]), which is not a subpart of the list, and thus, cannot be a match.

Note that we can't write a pattern to match the first and the last elements of a list simultaneously, either. A pattern has a depth that's fixed at compilation time.

Upvotes: 6

Adam Bergmark
Adam Bergmark

Reputation: 7536

Pattern matching works on constructors, : is the only list constructor so you can not match on the middle of the list. You need to construct the new list backwards (obviously :) ) which can be done by taking the head and appending that to the reverse of the rest of the list.

Upvotes: 5

Related Questions