2014-11-09 5 views
2

Я пишу мелкие функции, чтобы нарезать строку в пакетах заданной длины, но я новичок в Haskell, и я думаю, что мог бы упростить свои функции. Вот они:Упрощение функций Haskell

packetAux _ [] = [] 
packetAux 0 ls = [] 
packetAux n [email protected](x:xs) = if n > (length l) then [] else x : packetAux (n - 1) xs 

packet _ [] = [] 
packet 0 l = [] 
packet n [email protected](x:xs) = [x | x <- ((packetAux n l) : (packet n xs)), x /= ""] 

Ex: пакет 2 "12345" дает [ "12", "23", "34", "45"]

Как я могу избежать 1) повторы в packetAux и пакет 2) фильтрация результата в пакете с x/= ""?

ответ

2

Общий трюк - использовать Hoogle или Hayoo! чтобы проверить, не существует ли подобной функции. подпись пакета является:

Int -> [Char] -> [[Char]] 

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

Int -> [a] -> [a] 

Он принимает «n» - первые элементы данного списка.

Это поможет нам уменьшить основную часть функции:

packet n (x:xs) = [[x] ++ take (n-1) xs] ++ packet n xs 

Теперь, так как вы не хотите, чтобы функция возвращала значение, когда длина списка меньше п значения, мы можем использовать охранников, чтобы держать вещи простыми:

packet n [email protected](x:xs) 
    | length l < n = [] 
    | otherwise = [[x] ++ take (n-1) xs] ++ packet n xs 

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

+1

'[х] ++ 'так же, как' х: '. – chaosmasttter

+0

Спасибо за улучшение! – user3166747

5

Ваша функция

import Data.List (tails) 

packets :: Int -> [a] -> [[a]] 
packets n xs = filter ((==n).length) $ map (take n) $ tails xs 

Другой способ написать это

packets n xs = foldr (zipWith (:)) (repeat []) $ take n $ tails xs 

Оба варианта будут реально работать на бесконечных списках тоже , продуктивно.

$ оператор только для легкой группировки без скобок:

f $ g $ x = f (g (x)) 
+0

Спасибо за решения, 1-е решение намного быстрее, чем мое, но второе не работает с чем-то, где n равно 0: он дает бесконечное ... »,« "," "," "," , "", ... На самом деле пакеты с длиной 0 не очень полезны! Еще раз спасибо! – user3166747

+0

, 2-й вариант отвечает на ваш '2)', а 1-й избегает лишних переходов списка вашего '1' '(мимо первых' n' элементов списка). Ваша длина l

+0

Почему не 'пакеты n xs = takeWhile ((== n) .length) $ map (взять n) $ tails xs'? – user3237465

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