Что такое параморфизмы?

Читая черезэта классическая бумагаЯЯ застрял на параморфизмах. К сожалению, раздел довольно тонкий, а страница Википедии неничего не скажешь.

Мой перевод на Haskell:

para :: (a -> [a] -> b -> b) -> b -> [a] -> b
para f base = h
  where
    h []       =   base
    h (x:xs)   =   f x xs (h xs)

Но я нея не понимаюУ меня нет интуиции для подписи типа или желаемого результата.

Какие'Является ли параморфизм, и каковы некоторые полезные примеры в действии?

Да я'виделэти вопросыно они неt охватывает параморфизмы напрямую и указывает только наРесурсы это может быть полезно в качестве ссылок, но не в качестве учебных материалов.

 Daniel Fischer10 нояб. 2012 г., 00:18
para f base xs = foldr (uncurry f) base $ zip xs (tail $tails xs)Метинкс.
 huon10 нояб. 2012 г., 00:23
В соответствии сэта вики-страница, параморфизмы "модель примитивной рекурсии по индуктивным типам данных ", Означает ли это что-нибудь / помощь?
 stephen tetley10 нояб. 2012 г., 08:31
Джереми Гиббонс "Деление» статья, на которую я указал в комментарии к одному из этих вопросов, является очень полезным учебным материалом.cs.ox.ac.uk/jeremy.gibbons/publications/fission.pdf Это работает через многочисленные рекурсивные паттерны очень четко.
 Will Ness15 июл. 2013 г., 09:54
Daniel»переписатьможно упростить как para f base xs = foldr g base (init $ tails xs) where g (x:xs) = f x xs, Это напоминаетОбыкновенный Лисп.maplist

Ответы на вопрос(1)

Решение Вопроса

Да, этоpara, Сравните с катаморфизмом или:foldr

para  :: (a -> [a] -> b -> b) -> b -> [a] -> b
foldr :: (a ->        b -> b) -> b -> [a] -> b

para  c n (x : xs) = c x xs (para c n xs)
foldr c n (x : xs) = c x    (foldr c n xs)
para  c n []       = n
foldr c n []       = n

Некоторые люди называют параморфизмыпримитивная рекурсия " в отличие от катаморфизмов (foldr) существоитерация».

Куда 'foldrs два параметра задаются рекурсивно вычисляемым значением для каждого рекурсивного подобъекта входных данных (здесь этоХвост списка), 'paraПараметры s получают как исходный подобъект, так и значение, вычисленное из него рекурсивно.

Пример функции, которая 'хорошо выражено сpara это коллекция правильных списков.

suff :: [x] -> [[x]]
suff = para (\ x xs suffxs -> xs : suffxs) []

чтобы

suff "suffix" = ["uffix", "ffix", "fix", "ix", "x", ""]

Возможно, еще проще

safeTail :: [x] -> Maybe [x]
safeTail = para (\ _ xs _ -> Just xs) Nothing

в котором "минусы» ветвь игнорирует свой рекурсивно вычисленный аргумент и просто возвращает хвост. Оцениваемый лениво, рекурсивные вычисления никогда не происходят, и хвост извлекается за постоянное время.

Вы можете определитьfoldr с помощьюpara довольно легко; Это'немного сложнее определитьpara отfoldr, но это'Это, конечно, возможно, и каждый должен знать, как этосделано!

foldr c n =       para  (\ x  xs  t ->           c x    t)       n
para  c n = snd . foldr (\ x (xs, t) -> (x : xs, c x xs t)) ([], n)

Хитрость в определенииpara сfoldr это реконструироватькопия исходных данных, так что мы получаем доступ к копии хвоста на каждом этапе, даже если у нас не было доступа к оригиналу. В конце,snd отбрасывает копию ввода и дает только выходное значение. Это'не очень эффективно, но если вызаинтересованы в явной выразительности,para дает вам не больше, чемfoldr, Если вы используете этоfoldrкодированная версияpara, затемsafeTail все равно будет занимать линейное время, копируя хвостовой элемент за элементом.

Чтобы'сидеть:para это более удобная версияfoldr который дает вам немедленный доступ к хвосту списка, а также к значению, вычисленному из него.

В общем случае работа с типом данных, сгенерированным как рекурсивная точка фиксации функтора

data Fix f = In (f (Fix f))

у тебя есть

cata :: Functor f => (f         t  -> t) -> Fix f -> t
para :: Functor f => (f (Fix f, t) -> t) -> Fix f -> t

cata phi (In ff) = phi (fmap (cata phi) ff)
para psi (In ff) = psi (fmap keepCopy   ff) where
  keepCopy x = (x, para psi x)

и опять-таки, оба являются взаимно определимыми, сpara определяется изcata к тому жесделать копию" трюк

para psi = snd . cata (\ fxt -> (In (fmap fst fxt), psi fxt))

Снова,para не более выразителен, чемcata, но удобнее, если вам нужен легкий доступ к подструктурам ввода.

Редактировать: Я вспомнил еще один хороший пример.

Рассмотрим двоичные деревья поиска, заданныеFix TreeF где

data TreeF sub = Leaf | Node sub Integer sub

и попробуйте определить вставку для двоичных деревьев поиска, сначала какcataтогда какpara, Вы'найдуpara Версия намного проще, так как на каждом узле вам нужно будет вставить в одно поддерево, но сохранить другое как было

Ваш ответ на вопрос