2015-02-10 3 views
-1

Как изменить приведенную ниже функцию так, чтобы случай, когда список короче, чем поиск индекса, приведет к ошибке.Список индексов Haskell за пределами границ

elementAt::Int -> [Int] -> Int 
elementAt = Data.Foldable.foldl (\x y -> if x == 0 then y else x-1) 

1 является индексом первого элемента

+2

Я думаю, что эта функция неверна, даже если вы попытаетесь получить элемент в диапазоне списка. Например, 'elementAt 0 [1, 2, 3]' вернет '3'. – WilQu

+0

Я считаю, что явная рекурсия проще использовать в этом случае, чем складки. – chi

+0

1 считается элементом индекса, который я забыл упомянуть, таким образом, 0 считается за пределами – yonutix

ответ

6

Используя складку, чтобы найти п-й элемент в списке является довольно сложным способом. Я хочу представить вам простой способ с использованием явной рекурсии:

Вы должны взглянуть на эту проблему по-разному:

  1. Что такое мой базовый случай?
  2. Как должен выглядеть рекурсивный вызов?
  3. (необязательно) Как насчет ошибок?

сигнатура типа метода будет дан:

elementAt :: Int -> [Int] -> Int 

только беспокоиться о первой точке, мы знаем, что если индекс 0, мы хотим вернуть этот элемент:

elementAt 1 (x:_) = x 

Теперь, если наш номер больше 1? В этом случае мы хотим уменьшить наш индексный конец предиката на следующий товар:

elementAt n (x:xs) = elementAt (n-1) xs 

Теперь мы почти закончили! Если мы хотим, чтобы бросить ошибку, если элемент в указанной позиции не найден, мы можем просто использовать error:

elementAt _ _ = error "Element not found!" 

Но это не то, как работает идиоматическое Haskell способом. Одним из возможных решений является использование Maybe обернуть результат в Для этого мы должны изменить тип подписи немного:.

elementAt :: Int -> [Int] -> Maybe Int 

Теперь функция может вернуть Just элемент в указанной позиции, если она существует и Nothing иначе:

elementAt 1 (x:_) = Just x 
elementAt n (x:xs) = elementAt (n-1) xs 
elementAt _ _  = Nothing 

для полноты картины, то здесь один из возможных способов для достижения этой цели, хотя складку:

elementAt n = foldl (\acc x -> if fst x == n then snd x else acc) n . zip [1..n] 
+0

Кажется хорошим ответом, у меня есть более короткий способ сделать это, спасибо! – yonutix

+0

@CosminMihai Существует более короткий способ сделать это, но я могу пообещать вам, что его не так просто реализовать/прочитать. – ThreeFx

+0

Неважно, что было целью вопроса, чтобы найти более короткий способ сделать это, если вы знаете лучший способ, поделитесь им, пожалуйста, – yonutix

Смежные вопросы