recursion-algorithms

Extra Recursion Schemes

{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE RankNTypes #-}
module RecursionSchemes.Extra where

import Control.Monad ((>=>))
import Data.Bifunctor

import Control.Comonad
import Control.Comonad.Cofree
import Control.Foldl
import Data.Functor.Foldable

Here is a collection of implementations of recursion schemes that are not implemented in recursion-schemes.

Dynamorphism

Dynamorphism is the recursion schemes proposed by Kabanov and Vene to realize dynamic programming[^1]. Simply put, it is represented as a refold of Anamorphism and Histomorphism.However, here we implement Dynamorphism as an extension of Hylomorphism in order not to lose generality.

dyna :: Functor f => (f (Cofree f x) -> x) -> (y -> f y) -> (y -> x)
dyna phi psi = extract . hylo ap psi
  where ap f = phi f :< f

Multimorphism

Multimorphism is a recursion schemes that deals with the two recursive type at the same time[^2].

mmulti :: (Recursive f, Recursive g) => (forall a b. (a -> b -> c) -> Base f a -> Base g b -> c) -> f -> g -> c
mmulti psi f g = psi (mmulti psi) (project f) (project g)

mmulti can also be implemented using Day convolution as type (Day (Base f) (Base g) c -> c) -> f -> g -> c[^3].

Since Co f is the right adjoint of Day f, we can rewrite mmulti using transpose[^4].

mmulti' :: (Recursive f, Recursive g) => (forall r. Base g c -> Base f (c -> r) -> r) -> f -> g -> c

Monoidal Catamorphism

This idea was introduced by Bartosz Milewski as an extension of Foldl to RecursionSchemes[^5]. Here we use endomorphsm instead of monoids to match the implementation in the Foldl library.

type FoldAlgebra f = forall x. f (x -> x) (x -> x) -> (x -> x)

cat :: (Bifunctor f, Functor (f a)) => FoldAlgebra f -> Fold a b -> Fix (f a) -> b
cat falg (Fold step begin done) = done . ($ begin) . cata (falg . bimap (flip step) id)

Monadic Recursion Schemes

Monadic catamorphism[^6] can be implemented as a special case of ordinary catamorphism[^7].

cataM :: (Traversable (Base t), Monad m, Recursive t)
      => (Base t c -> m c) -> t -> m c
cataM = cata . (sequence >=>)

You can also implement monadic paramorphism in a similar way.

paraM :: (Recursive t, Monad m, Traversable (Base t))
      => (Base t (t, c) -> m c) -> t -> m c
paraM = para . (sequence . fmap sequence >=>)

References

[1] Kabanov, Jevgeni, and Varmo Vene. “Recursion schemes for dynamic programming.” International Conference on Mathematics of Program Construction. Springer, Berlin, Heidelberg, 2006.
[2] Uustalu, Tarmo, and Varmo Vene. “Coding recursion a la Mendler.” Department of Computer Science, Utrecht University. 2000.
[3] sellout/yaya - Yaya.Fold#cata2
[4] kan-extensions - Control.Monad.Co
[5] Monoidal Catamorphisms | Bartosz Milewski’s Programming Cafe
[6] Fokkinga, Maarten Maria. Monadic maps and folds for arbitrary datatypes. University of Twente, Department of Computer Science, 1994.
[7] Suggestion: Add monadic variants of various …morphism functions. · Issue #3 · ekmett/recursion-schemes