yaya: Total recursion schemes.

[ agpl, library, recursion ] [ Propose Tags ]

Recursion schemes allow you to separate recursion from your business logic – making your own operations simpler, more modular, and less error-prone. This library also provides tools for combining your operations in ways that reduce the number of passes over your data and is designed to encourage total (i.e., successfully terminating) functions.

[Skip to Readme]


Maintainer's Corner

Package maintainers

For package maintainers and hackage trustees


  • No Candidates
Versions [RSS],,,,,,,,,,,,,, (info)
Change log CHANGELOG.md
Dependencies base (>=4.12.0 && <4.13 || >=4.13.0 && <4.14 || >=4.14.0 && <4.15 || >=4.15.0 && <4.16 || >=4.16.0 && <4.17 || >=4.17.0 && <4.18 || >=4.18.0 && <4.19 || >=4.19.0 && <4.20), comonad (>=5.0.7 && <5.1), either (>=5 && <5.1), foldable1-classes-compat (>=0.1 && <0.2), free (>=5.1.5 && <5.3), kan-extensions (>=5.2 && <5.3), lens (>=5 && <5.3), profunctors (>=5.5.2 && <5.7), strict (>=0.4 && <0.6), template-haskell (>=2.14.0 && <2.15 || >=2.15.0 && <2.16 || >=2.16.0 && <2.17 || >=2.17.0 && <2.18 || >=2.18.0 && <2.19 || >=2.19.0 && <2.20 || >=2.20.0 && <2.21 || >=2.21.0 && <2.22), th-abstraction (>=0.4.1 && <0.5 || >=0.6.0 && <0.7), transformers (>=0.5.5 && <0.6 || >=0.6.1 && <0.7) [details]
License AGPL-3.0-or-later
Copyright 2017 Greg Pfeil
Author Greg Pfeil <greg@technomadic.org>
Maintainer Greg Pfeil <greg@technomadic.org>
Category Recursion
Home page https://github.com/sellout/yaya#readme
Bug tracker https://github.com/sellout/yaya/issues
Source repo head: git clone https://github.com/sellout/yaya
Uploaded by sellout at 2024-04-03T14:56:05Z
Reverse Dependencies 4 direct, 0 indirect [details]
Downloads 3208 total (37 in the last 30 days)
Rating (no votes yet) [estimated by Bayesian average]
Your Rating
  • λ
  • λ
  • λ
Status Docs available [build log]
Last success reported on 2024-04-03 [all 1 reports]

Readme for yaya-

[back to package description]


Yet another … yet another recursion scheme library for Haskell


Recursion schemes allow you to separate any recursion from your business logic, writing step-wise operations that can be applied in a way that guarantees termination (or, dually, progress).

How's this possible? You can’t have totality and Turing-completeness, can you? Oh, but you can – there is a particular type, Partial a (encoded with a fixed-point) that handles potential non-termination, akin to the way that Maybe a handles exceptional cases. It can be folded into IO in your main function, so that the runtime can execute a Turing-complete program that was modeled totally.

NB: The tests for this package are unfortunately included in yaya-hedgehog instead, to avoid a dependency cycle.


This organization is intended to make this a lightly-opinionated library. You should only need to import one module (per package) into any module of yours.

  • Pattern – This is what you should use most of the time. It provides common pattern functors that aren’t found elsewhere as well as other operations that are useful when you’re defining your own algebras.
  • Fold – This (and its submodules) provides algebra transformers, fixed-point operators, and other things you use when applying folds.
  • Retrofit – Utilities for making your existing data types compatible with recursion schemes.
  • Applied – A number of commonly-useful utilities defined as folds. Intended both as examples and code that you can actually use in your projects.
  • Zoo – Names that you may have seen in the recursion scheme literature, but that we generally avoid using here. In general, prefer the right-hand side of these definitions, which shouldn’t require importing this module.

Some (hopefully) helpful guidelines

Greek characters (and names) for things can often add confusion, however, there are some that we’ve kept here because I think (with the right mnemonic) they're actually clarifying.

  • φ – an algebra – “phi” (pronounced /faɪ/)
  • ψ – a coalgebra – “psi” (pronounced /ˈ(p)saɪ/)

These are the symbols used in “the literature”, but I think they also provide a good visual mnemonic – φ, like an algebra, is folded inward, while ψ, like a coalgebra, opens up. So, I find these symbols more evocative than f and g or algebra and coalgebra, or any other pair of names I’ve come across for these concepts.

There are two other names, Mu and Nu (for the inductive and coinductive fixed-point operators), that I don’t think have earned their place, but I just haven’t come up with something more helpful yet.

Naming Conventions

There's a set of conventions around the naming of the operations. There are many variants of each operation (and they're all ultimately variants of cata and ana), so understanding this convention should help make it easier to understand the myriad possibilities rather than learning them by rote. The general pattern is



“Generalized” variant – This parameterizes the fold over some DistributiveLaw that generalizes the (co)algebra over some Monad or Comonad. This is normally only applied to the fundamental operations – cata, ana, and hylo, but there is also a gapo (dual to zygo) that really only coincidentally follows this naming pattern.

Many of the other “well-known” named folds are specializations of this:

  • when specialized to ((,) T), it’s para;
  • when ((,) B), zygo;
  • when Free f, futu;
  • etc.


“Elgot” variant – Named after the form of coalgebra used in an “Elgot algebra”. If there is an operation that takes some f (x a) -> a, the Elgot variant takes x (f a) -> a, which often has similar but distinct properties from the original.

As a mnemonic, you can read the e as “exterior” as with a regular generalized fold, the x is on the inside of the f, while with the Elgot variant, it's on the outside of the f.


“Transformer” variant – For some fold that takes an algebra like f (x a) -> a, and where t is the (monad or comonad) transformer of x, the transformer variant takes an algebra like f (t m a) -> a.


Kleisli (“monadic”) variant – This convention is much more widespread than simply recursion schemes. A fold that returns its result in a Monad, by applying a Kleisli algebra (that is, f a -> m a rather than f a -> a. The dual of this might be something like anaW (taking a seed value in a Comonad), but those are uninteresting. Having Kleisli variants of unfolds is unsafe, as it can force traversal of an infinite structure. If you’re looking for an operation like that, you are better off with an effectful streaming library.