Попытка изучить Haskell. Я пытаюсь записать, простая функция для удаления числа из списка, не используя встроенную функцию (удалить... Я думаю). Ради простоты давайте предположим, что входным параметром является Целое число, и список является Целочисленным списком. Вот код, который я имею, скажите мне что случилось со следующим кодом
areTheySame :: Int -> Int-> [Int]
areTheySame x y | x == y = []
| otherwise = [y]
removeItem :: Int -> [Int] -> [Int]
removeItem x (y:ys) = areTheySame x y : removeItem x ys
Другие правы, что проблема является оператором :
. Я бы сказал, что ваш функция Aretheysame
, которая возвращает список, это неправильный подход, хотя. Вместо того, чтобы перейти к оператору ++
, лучшая реализация этой функции будет:
removeItem _ [] = []
removeItem x (y:ys) | x == y = removeItem x ys
| otherwise = y : removeItem x ys
, как вы можете видеть, это довольно простая реализация. Кроме того, консиция, как это намного меньше налогообложения для вашей программы, чем добавление куча списков вместе. У него также есть другие преимущества, такие как работающие лениво.
для справки, вам может быть заинтересован в виде просмотра , как это сделано в Удалить
из данных. Список .
Вы могли бы уйти Aretheysame
Aretheysame
, как есть, но вам нужно использовать CONCATMAP
в RESHINGITEM
, чтобы свернуть пустые списки:
removeItem :: Int -> [Int] -> [Int]
removeItem x xs = concatMap (areTheySame x) xs
или эквивалентно
removeItem :: Int -> [Int] -> [Int]
removeItem x = concatMap (areTheySame x)
Обратите внимание, что типы ваших функций могут быть более общими:
areTheySame :: (Eq a) => a -> a -> [a]
removeItem :: (Eq a) => a -> [a] -> [a]
Это позволяет удалять элементы из списков любого типа, для которого определяется ==
, не только int
Отказ
:
Оператор не делает то, что вы думаете, что он делает: :
:
(:) :: a -> [a] -> [a]
требуется элемент типа A
и добавляет его в начало списка типов А
. Вы используете его для объединения двух списков типа A
. Для этого вам нужно использовать ++
:
(++) :: [a] -> [a] -> [a]
Кроме того, если вы делаете рекурсивную функцию, ему необходимо окончательное состояние. Попробуйте это:
removeItem _ [] = []
removeItem x (y:ys) = areTheySame x y ++ removeItem x ys
Таким образом, когда вы дойдете до конца списка, функция перестанет рекурсировать.
Вы также можете сделать это как понимание списка
delete :: Eq a => a -> [a] -> [a]
delete deleted xs = [ x | x <- xs, x /= deleted ]
Это минимальное исправление, чтобы Ваш пример заработал:
removeItem :: Int -> [Int] -> [Int]
removeItem _ [] = []
removeItem x (y:ys) = areTheySame x y ++ removeItem x ys
Во-первых, Вам нужно использовать ++
для объединения списков, так как оператор :
, используемый Вами, добавляет только один элемент в начало списка (он не может быть использован ни для добавления списков с одним элементом, ни для добавления пустых списков). Сначала Вы сравниваете заголовок списка (y
) с элементом, который хотите удалить, и правильно возвращаете элемент или пустой список, используя isTheySame
. Затем необходимо рекурсивно продолжить использование removeItem
на остальной части списка (ys
). Полученный список необходимо скомпоновать, используя ++
.
Во-вторых, как отметил Крис Лутц, вам нужно условие завершения, когда вы дойдете до конца списка. Добавляя эту строку, Хаскелл знает, что делать с пустым списком (то есть ничего, просто вернуть пустой список).
Как сказал Чак, вы можете упростить код для этой задачи, если removeItem не делегирует задачу сравнения, а сравнивает себя и выбрасывает элемент, если его нужно удалить, в противном случае держите его в заголовке списка (используя :
). В любом случае, продолжайте рекурсивно с остальным списком.
-- nothing can be removed from an empty list
-- ==> return empty list and stop recursion
removeItem _ [] = []
-- if the list is not empty, cut off the head in y and keep the rest in ys
-- if x==y, remove y and continue
removeItem x (y:ys) | x == y = removeItem x ys
-- otherwise, add y back and continue
| otherwise = y : removeItem x ys
Я считаю, что все приведенные до сих пор решения работают иначе, чем Data.List.delete, который удаляет только первый член.
deleteFromList x xs =
case break (==x) xs of
(_,[]) -> xs
(notsat,sat) -> notsat ++ tail sat
была моей попыткой удалить только первого участника (еще не достигнув пика в D.L.).
Неясно, какого поведения хочет главный постер.