README
Yaya
Yet another … yet another recursion scheme library for Haskell.
Overview
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 is 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.
organization
- [
yaya](core/README.md) – the safe operations and data types for working with recursion - [
yaya-hedgehog](hedgehog/README.md) – utilities for testing your Yaya-using code with Hedgehog - [
yaya-unsafe](unsafe/README.md) – unsafe instances and operations
other libraries
Turtles
Yaya is a sister library to Turtles – the same approach, but implemented in Scala. Here are some differences to be aware of:
- the
Zoomodules in Turtles are both larger and their use is more encouraged, because Scala’s inference makes it harder to usegcataetc. directly; - the
UnsafeandNativemodules have different contents, because different structures are strict or lazy between the two languages. E.g., in Scala,scala.collection.immutable.Listis strict, so theRecursiveinstance is inNative, while theCorecursiveinstance is inUnsafe, but Haskell’sData.Listis lazy, so theCorecursiveinstance is inNativewhile theRecursiveinstance is inUnsafe.
Differences from recursion-schemes
- uses multi-parameter type classes rather than a type family for the
Basefunctor, because the latter frequently requires constraints in the form ofRecursive t, Base t ~ f, so we preferRecursive t f. - total operations, with anything potentially partial relegated to the
yaya-unsafepackage, which has consequences:Recursive (Mu f) fandCorecursive (Nu f) fare the only “safe” instances of recursive data types
- a separate
Steppableclass withprojectandembed, increasing the number of operations that can be defined without needing unsafe instances. - relatively few operations are defined, with the intent being that
g{cata|ana}be used directly instead. The more commonly known operations are provided in theZoomodules, with the intent that they provide a mapping from names you may have heard to how Yaya expects you to accomplish them. - pattern functors tend to be named independently of their fixed-points. E.g., we use
Maybedirectly instead of someNatF,XNor a binstead ofListF, anda `AndMaybe` binstead ofNonEmptyF.
NB: There are a number of instances (e.g., Corecursive [a] (XNor a)) that are actually safe, but they rely on Haskell’s own recursion. We could potentially add a module/package in between the safe and unsafe ones, containing Corecursive instances for types that are lazy in their recursive parameters and Recursive instances for ones that are strict.
Non-philosophical differences:
- no TH yet – this might be a philosophical difference, actually. On the one hand, it useful to be able to migrate existing code by quickly creating a pattern functor, but on the other, this stuff is generally unsafe. So, it should at least be relegated to
yaya-unsafe. - Yaya has productive metamorphisms (
stream, etc.). The naïve composition ofcataandanahas no benefits, but it has been difficult to generalize Gibbons’ streaming transformers to data structures other than lists.
Differences from compdata
I’m not as familiar with compdata, so I’ll have to look at it more before fleshing this out.
Non-philosophical differences
- no type-indexed recursion schemes – ideally Yaya would achieve this via PolyKinds.