Haskell - get the nth element without "!!"

Hi, I need to get the nth element of the list, but without using !! operator. I am extremely new to haskell, so I would appreciate it if you could answer in more detail, and not just one line of code. This is what I'm trying at the moment:

nthel:: Int -> [Int] -> Int nthel n xs = 0 let xsxs = take n xs nthel n xs = last xsxs 

But I get: parsing error (possibly wrong indent)

Thank you in advance!

+7
source share
4 answers

There are a lot of things there,

 nthel :: Int -> [Int] -> Int 

technically correct, really we want

 nthel :: Int -> [a] -> a 

Therefore, we can use this in lists of anything (optional)

 nthel n xs = 0 

What you just said is "No matter what you give nthel return 0". which is clearly wrong.

 let xsxs = ... 

This is simply not a legitimate haskell. let ... in ... is an expression, it cannot be used to fill.

From there, I'm not quite sure what this should do.

Perhaps this will help put you on the right track.

 nthelem n [] = <???> -- error case, empty list nthelem 0 xs = head xs nthelem n xs = <???> -- recursive case 

Try filling out <???> your best guess, and I will be happy to help from there.

Alternatively, you can use the Haskell pattern matching syntax. I will explain how you can do this with lists here .

This changes our value higher to

 nthelem n [] = <???> -- error case, empty list nthelem 0 (x:xs) = x --bind x to the first element, xs to the rest of the list nthelem n (x:xs) = <???> -- recursive case 

This is convenient as it negates the need to use explicit head and tail s.

+12
source

I think you meant this:

 nthel n xs = last xsxs where xsxs = take n xs 

... which you can simplify as:

 nthel n xs = last (take n xs) 
+8
source

I think you should avoid using last whenever possible - lists are made for use from the "front end" and not from the back. You want to get rid of the first n elements, and then get the head of the remaining list (of course, you will get an error message if the rest is empty). You can express it directly like this:

 nthel n xs = head (drop n xs) 

Or shorter:

 nthel n = head . drop n 

Or a little crazy:

 nthel = (head .) . drop 
+1
source

As you know, the list is not indexed, but it can be overcome with general tips.

Try ghci, zip [0..] "hello" , but what about zip [0..] "hello" zip [0,1,2] "hello" or zip [0..10] "hello" ?
Based on this observation, now we can easily get a way to index our list.
It is also a good illustration of the use of laziness, a good hint for your learning process.

Then, based on this and using pattern matching, we can provide an efficient algorithm.

  • Management of restrictive cases (empty list, negative index).
  • Replace the list by indexed version with a zipper.
  • A function call of a helper function to recursively transform our indexed list.

Now, for an auxiliary function, the list cannot be empty, then we can least match the template and

  • if our index is n, we have a winner
  • else if our next element is empty over
  • else, call the helper function with the next element.

In addition, since our function may fail (empty list ...), it would be nice to wrap our result using the Maybe type.

Putting it all together, we are done.

 nth :: Int -> [a] -> Maybe a nth n xs | null xs || n < 0 = Nothing | otherwise = helper n zs where zs = zip [0..] xs helper n ((i,c):zs) | i == n = Just c | null zs = Nothing | otherwise = helper n zs 
0
source

All Articles