99 questions/Solutions/3

From HaskellWiki
< 99 questions‎ | Solutions
Revision as of 11:08, 12 September 2012 by Jkoshy (talk | contribs) (Tweak code layout; add an example showing erroneous behavior.)
Jump to navigation Jump to search
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.

(*) Find the K'th element of a list. The first element in the list is number 1.

This is (almost) the infix operator !! in Prelude, which is defined as:

(!!)                :: [a] -> Int -> a
(x:_)  !! 0         =  x
(_:xs) !! n         =  xs !! (n-1)

Except this doesn't quite work, because !! is zero-indexed, and element-at should be one-indexed. So:

elementAt :: [a] -> Int -> a
elementAt list i    = list !! (i-1)

Or without using the infix operator:

elementAt' :: [a] -> Int -> a
elementAt' (x:_) 1  = x
elementAt' [] _     = error "Index out of bounds"
elementAt' (_:xs) k
  | k < 1           = error "Index out of bounds"
  | otherwise       = elementAt' xs (k - 1)

Alternative version:

elementAt'' :: [a] -> Int -> a
elementAt'' (x:_) 1  = x
elementAt'' (_:xs) i = elementAt'' xs (i - 1)
elementAt'' _ _      = error "Index out of bounds"

This does not work correctly on invalid indexes and infinite lists, e.g.:

elementAt'' [1..] 0

A few more solutions using prelude functions:

elementAt_w' xs n = last . take n $ xs -- wrong
-- Main> map (elementAt_w' [1..4]) [1..10]
-- [1,2,3,4,4,4,4,4,4,4]
elementAt_w'' xs n = head . reverse . take n $ xs -- wrong
-- Main> map (elementAt_w'' [1..4]) [1..10]
-- [1,2,3,4,4,4,4,4,4,4]
elementAt_w''' xs n = head . drop (n - 1) $ xs -- wrong
-- Main> map (elementAt_w''' [1..4]) [0..10]
-- [1,1,2,3,4,*** Exception: Prelude.head: empty list

or elementAt_w' correctly in point-free style:

elementAt_w'pf = (last .) . take . (+ 1)