2017-01-19 5 views
1

Как я могу написать takeWhile, который сохранит первый элемент, который не соответствует условию?Haskell takeWhile + 1

Пример (очевидно, мой пример сложнее, чем это):

Вместо takeWhile (\× - > x! = 3) [1..10] вернуть [1,2] мне нужно [1,2,3].

Я думал (takeWhile myFunc myList) ++ [find myFunc myList], но это означает, что я должен пройти через мой список 2 раза ...

Любая идея?

+0

Вы считаете, что это «складка»? Используя шаблон 'foldr step base', вы можете написать любую функцию, подобную этой в списках. –

+0

В случае, если из ответа Чи не ясно, что 'takeWhile' и другие' base' функции не являются магии: они реализованы в haskell, и вы можете просмотреть исходный код, скопировать-вставить и изменить их и т. Д. Большинство из них - однострочные. – jberryman

ответ

6

Вы можете бросить свой собственный.

takeWhileOneMore :: (a -> Bool) -> [a] -> [a] 
takeWhileOneMore p = foldr (\x ys -> if p x then x:ys else [x]) [] 

Сравните с

takeWhile :: (a -> Bool) -> [a] -> [a] 
takeWhile p = foldr (\x ys -> if p x then x:ys else []) [] 

Явной рекурсией будет также отлично подходит для этого.

takeWhileOneMore :: (a -> Bool) -> [a] -> [a] 
takeWhileOneMore p [] = [] 
takeWhileOneMore p (x:xs) = 
    if p x 
    then x : takeWhileOneMore p xs 
    else [x] 
+0

Спасибо! Я понимаю, что мне еще недостаточно комфортно с 'foldr'. Я думал о 'takeWhileOneMore p list = take (fromJust. FindIndex (not. P) list). Это тоже правильно, не так ли? Как вы сравниваете 2 решения? –

+2

@AugustinRiedinger 'fromJust' лучше всего избегать. Это приведет к сбою вашей программы при подаче с помощью «Ничего». Все потенциально сбойные функции, такие как 'head, tail, fromJust, ...', редко необходимы, и обычно лучше работать, делая вид, что их не существует, используя сопоставление шаблонов и/или более безопасные («итоговые») функции. Я добавил более базовую альтернативу выше, без 'foldr'. – chi

8

Вы можете использовать span или break.

λ> span (/=3) [1..10] 
([1,2],[3,4,5,6,7,8,9,10]) 

Так что вы можете сделать что-то вроде этого:

takeWhileInc :: (a -> Bool) -> [a] -> [a] 
takeWhileInc p xs = case zs of [] -> error "not found" 
           (z:_) -> ys ++ [z] 
    where 
    (ys, zs) = span p xs 

(. Или все, что вы хотите, чтобы это произошло, когда zs пуст, потому что ни 3 не было найдено)

0

Я хотел бы использовать базовая функция больше, чем многие люди, например, повторно использовать takeWhile интеллектуальным способом получения желаемого результата. Например, вы можете создать новый список предикатов с первым элементом является True и takeWhile этот список верно:

takeWhileP1 p xs = map snd (takeWhile fst (zip (True:map p xs) xs) 

Это обобщает хорошо, как хорошо (не обязательно эффективны в таком виде):

takeWhilePlusN n p xs = map snd (takeWhile fst (zip (replicate n True ++ map p xs) xs)) 

Или, возможно, легче читать:

takeWhilePlusN n p xs = 
    let preds  = replicate n True ++ map p xs 
     annotated = zip preds xs 
    in map snd (takeWhile fst annotated) 

И результат:

*Main> takeWhilePlusN 3 (<5) [1..10] 
[1,2,3,4,5,6,7] 
*Main> takeWhilePlusN 1 (<5) [1..10] 
[1,2,3,4,5] 
*Main> takeWhileP1 (<5) [1..10] 
[1,2,3,4,5] 
*Main> takeWhile (<5) [1..10] 
[1,2,3,4] 
Смежные вопросы