часто помогает изобретать некоторый инвариант и записывать для него некоторые законы сохранения. Здесь обратите внимание, что
reverse xs = reverse xs ++ []
reverse (x:xs) = (reverse xs ++ [x]) ++ []
= reverse xs ++ ([x] ++ [])
= reverse xs ++ (x:[])
reverse (x:(y:xs)) =
= reverse (y:xs) ++ (x:[])
= reverse xs ++ (y:x:[])
......
reverse (x:(y:...:(z:[])...)) =
= reverse [] ++ (z:...:y:x:[])
так, если мы определим
reverse xs = rev xs [] where
rev (x:xs) acc = rev xs (x:acc)
rev [] acc = acc
мы установить. :) Т.е., для вызова rev a b
, конкатенаций реверсивного a
и b
сохраняются при преобразовании с головным элементом из a
и не предваряя его b
, доa
пусты, а затем это просто b
. Это может даже быть выражено с использованием higher-order function until
после описания английского как
{-# LANGUAGE TupleSections #-}
reverse = snd . until (null.fst) (\(a,b)-> (tail a,head a:b)) . (, [])
Мы также можем сейчас определить, например, revappend
функции, используя точно такую же внутреннюю функцию с немного подправить, как мы его называем:
revappend xs ys = rev xs ys where
rev (x:xs) acc = rev xs (x:acc)
rev [] acc = acc
делает '[длина хз - 1, длина хз - 2..0]' работа? –
Если вам пока не нравится рекурсия, прежде чем смотреть на другие реализации, попробуйте определить «обратный» другим способом, заполнив следующее: 'reverse [] = ...; reverse (x: xs) = ... 'и подумайте об этом как« обратная сторона пустого списка ... и обратная сторона 'x' соответствовала списку' xs' is ... " – jberryman
Обратите внимание, что это как правило, под вопросом для доступа к спискам по индексу. Они специально разработаны так, что вы можете легко деконструировать их _recursively_, от элемента head по элементу, но очень плохо выполняете, когда вы запрашиваете элемент в произвольном положении. – leftaroundabout