Проблема с вашей попыткой заключается в том, что когда вы говорите:
let ((n,m):ns) = zip [0..(length (x:xs))] (x:xs)
тогда n
всегда будет 0
. Это потому, что вы сопоставляете (n,m)
с первым элементом zip [0..(length (x:xs))] (x:xs)
, который всегда будет (0,x)
.
Само по себе это не проблема, но это означает, что вы должны правильно обработать рекурсивный шаг. То, как у вас это сейчас, positions _ _
, если не пусто, будет всегда иметь 0
в качестве первого элемента, потому что единственный способ позволить ему найти совпадение, это если он находится во главе списка, в результате чего индекс 0
. Это означает, что ваш результат всегда будет списком правильной длины, но со всеми элементами 0
- как вы видите.
Проблема не в вашей схеме рекурсии, а в том, что вы не модифицируете результат, чтобы учесть тот факт, что вы не всегда хотите, чтобы 0
добавлялся в начало результата список. Поскольку каждый рекурсивный вызов просто добавляет 1 к индексу, который вы хотите найти, все, что вам нужно сделать, это map
функция приращения (+1)
над рекурсивным результатом:
positions' :: Eq a => a -> [a] -> [Int]
positions' _ [] = []
positions' a (x:xs) =
let ((0,m):ns) = zip [0..(length (x:xs))] (x:xs)
in if (a == m) then 0:(map (+1) (positions' a xs))
else (map (+1) (positions' a xs))
(Обратите внимание, что я изменил ваш let
, чтобы он был явным, что n
всегда будет 0
- я предпочитаю быть явным таким образом, но это само по себе не меняет вывод.) Поскольку m
всегда связан с x
, а ns
вообще не используется, мы можем исключить let, вставив определение m
:
positions' :: Eq a => a -> [a] -> [Int]
positions' _ [] = []
positions' a (x:xs) =
if a == x
then 0 : map (+1) (positions' a xs)
else map (+1) (positions' a xs)
Вы можете продолжить выделять повторяющиеся map (+1) (positions' a xs)
, если хотите.
Кстати, вам не требовалась явная рекурсия, чтобы избежать понимания списка здесь. Во-первых, списки являются заменой для использования map
и filter
. Я собирался записать это явно, но я вижу, что @WillemVanOnsem дал это как ответ, поэтому я просто отсылаю вас к его ответу.
Другой способ, хотя, возможно, и неприемлемый, если вас попросят реализовать это самостоятельно, это просто использовать встроенную функцию elemIndices , которая делает именно то, что вы пытаетесь реализовать здесь.