Удаление определенных элементов из списков в Haskell - PullRequest
1 голос
/ 04 апреля 2019

Мне трудно совмещать Хаскелл и функциональное программирование в моей голове. То, что я пытаюсь сделать, это манипулировать строкой так, чтобы я печатал / возвращал определенные символы каждый раз на основе заданного числа. Например:

printing "testing" 2 = "etn"

printing "testing" 3 = "sn"

Я много читал в Интернете, и, насколько я понимаю, я могу добиться этого с помощью фильтрации и циклирования, но я не могу понять / понять синтаксис этого языка, чтобы получить работающую программу.

Ответы [ 2 ]

3 голосов
/ 04 апреля 2019

Я постараюсь описать мой мыслительный процесс, чтобы вы могли следовать. Эта функция соответствует шаблону создания списка вывода (здесь строка) из входного начального числа (здесь строка) путем повторного применения функции (здесь отбрасываются некоторые элементы). Таким образом, я выбираю реализацию с Data.List.unfoldr.

unfoldr :: (b -> Maybe (a, b)) -> b -> [a]

Хорошо, мне нужно превратить начальное значение b в (Maybe) вывод a и остальную часть строки. Я назову эту подфункцию f и передам в unfoldr.

printing s n = unfoldr f s
  where f b = case drop n b of
                [] -> Nothing
                (x:xs) -> Just (x,xs)

Оказывается, что попытка убрать голову с начала списка и вернуть Maybe также является распространенным паттерном. Это Data.List.uncons, поэтому

printing s n = unfoldr (uncons . drop n) s

Очень гладко! Поэтому я проверяю это, и вывод неправильный! Ваш указанный вывод на самом деле, например. для n=2 выбирает каждый второй символ, т.е. пропускает (n-1) символов.

printing s n = unfoldr (uncons . drop (n-1)) s

Я проверяю это снова, и оно соответствует желаемому результату. Уф!

2 голосов
/ 04 апреля 2019

Чтобы продемонстрировать языку Haskell некоторые альтернативные решения принятому ответу.

Использование понимания списка :

printing :: Int -> String -> String
printing j ls = [s | (i, s) <- zip [1 .. ] ls, mod i j == 0]

Использование рекурсия :

printing' :: Int -> String -> String 
printing' n ls 
    | null ls'    = []
    | otherwise   = x : printing' n xs
    where
    ls'         = drop (n - 1) ls
    (x : xs)    = ls' 

В обоих случаях я перевернул аргументы, чтобы было проще выполнить частичное применение: printing 5 например, это новая функция, которая будет давать каждый 5-й символ применительно к строке.

Обратите внимание, с незначительными изменениями они будут работать для любого списка

takeEvery :: Int -> [a] -> [a]
...