Haskell как удалить все 0 из списка до тех пор, пока один из элементов /= 0?

#list #haskell #recursion #guard

#Список #haskell #рекурсия #охранник

Вопрос:

Я новичок в Haskell и пытаюсь понять, как написать код, который отбрасывает все нули до тех пор, пока элемент списка не станет> 0.

Так , например:

Входные данные: [0,0,5,6,0]

Вывод: [5,6,0]

До сих пор я писал это:

 zeroUntil :: [Int] -> [Int]
zeroUntil [] = []
zeroUntil (x:xs)
    | x == 0 = drop x (xs)
    | otherwise = zeroUntil xs
 

Но каким-то образом вместо [5,6,0] я получаю [ ] .

Может кто-нибудь, пожалуйста, объяснить, что я сделал не так?

Комментарии:

1. Ваша реализация не соответствует вашему результату. При запуске на входе , который вы описываете, он не выдает [] , а наоборот [0,5,6,0] . Конечно, все еще неправильно: он реализует совершенно иную функцию, чем вы предполагаете. Но, пожалуйста, убедитесь, что ваши проблемы воспроизводимы, вставив ваш фактический код и выходные данные и дважды проверив их перед публикацией.

Ответ №1:

Вы можете использовать dropWhile :: (a -> Bool) -> [a] -> [a] и, таким образом, удалять элементы, если они являются нулями:

 zeroUntil :: [Int] -> [Int]
zeroUntil = dropWhile (0 ==) 

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

 zeroUntil :: [Int] -> [Int]
zeroUntil [] = []
zeroUntil (0:xs) = zeroUntil xs
zeroUntil (x:xs)
    | x > 0 = x : xs  -- ← end of recursion, return the list
    | otherwise = x : zeroUntil xs  -- ← yield x and recurse 

например:

 Prelude> zeroUntil [0,0,5,6,0]
[5,6,0]
Prelude> zeroUntil [0,-1,5,6,0]
[-1,5,6,0]
 

Ответ №2:

 zeroUntil :: [Int] -> [Int]
zeroUntil [] = []
zeroUntil (x:xs)
    | x == 0 = drop x (xs)
    | otherwise = [x]    (zeroUntil xs)
 

Вы должны добавить первый элемент ( x ) в список, возвращаемый рекурсивным вызовом, в противном случае вы возвращаете пустой список.