tags:

views:

375

answers:

5

I'm reading through Learn You a Haskell and reached a spot where I'm trying to move an element in a list to the head. I've come up with what I think is the naive way and I'm curious if someone can show me what the experienced Haskell programmer would do instead.

In this example, I have a list of Integers and I want to move the element '4', which would be index '3', to the head of the list.

let nums = [1, 2, 3, 4, 5]
(nums !! 3) : delete (nums !! 3) nums

returns [4, 1, 2, 3, 5].

What do you think?

A: 

What a co-incidence?
I was reading the same thing a few days back. Looked it up again & wrote it like following.

nums !! 3 : [x | x <- nums, (x == (num !! 3)) == False]
shahkalpesh
Two problems: First, duplicate elements are removed. Second (less of a problem), the not equal operator is (/=), as opposed to ( (a == b) == False).
Mark Rushakoff
Good catch. As you can see, I am a beginner. Thanks for correcting :)
shahkalpesh
+9  A: 

I would do it this way:

move n as = head ts : (hs ++ tail ts)
   where (hs, ts) = splitAt n as

splitAt splits a list at the given position, it returns the two parts that are created by the splitting (here hs and ts). The element that should be moved to the front is now at the beginning of ts. head ts returns just this first element of hs, tail ts returns everything but that first element. The result of the function are just these parts combined in the right order: hs concatenated with tail ts and prepended by the element head ts.

sth
toHead n l = let (xs, y:ys) = splitAt n l in y : xs ++ ys
Stephan202
sth: Could you describe it please to understand the code?
shahkalpesh
+8  A: 

Experienced Haskellers hardly ever using list indexing. I'd use break to avoid repeated traversals (assuming you want to match on element '4', not index '3'):

case break (== 4)  [1, 2, 3, 4, 5] of
    (a,x:xs) -> x:a ++ xs
    (a,xs)    -> a ++ xs

As in:

Prelude Data.List> case break (== 4)  [1, 2, 3, 4, 5] of (a,x:xs) -> x:a ++ xs; (a,xs) -> a ++ xs
[4,1,2,3,5]

We can do the same with indexing via 'splitAt':

Prelude Data.List> case splitAt 3  [1, 2, 3, 4, 5] of (a,x:xs) -> x:a ++ xs; (a,xs) -> a ++ xs
[4,1,2,3,5]
Don Stewart
Yes, it's matching on element 4 not on index '3'. Sorry for the confusion
afrosteve
+3  A: 

There's also

toHead n l = l !! n : take n l ++ drop (n+1) l

which may be a little easier to follow than using splitAt.

Norman Ramsey
isn't this slower than the splitAt version?
yairchu
Not clear after the optimizer gets done with it. Run with ghc -O and find out!
Norman Ramsey
+3  A: 

small modification on sth's solution:

toHead n xs = x : pre ++ post
  where (pre, x:post) = splitAt n xs

using pattern matching instead of head n tail

yairchu