• Stars
    star
    389
  • Rank 110,500 (Top 3 %)
  • Language
    Scala
  • License
    Apache License 2.0
  • Created almost 7 years ago
  • Updated 3 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

recursion schemes for cats; to iterate is human, to recurse, divine

Droste

Join the chat at https://gitter.im/higherkindness/droste

Droste is a recursion library for Scala.

SBT installation

Select a tagged release version (x.y.z) and then add the following to your SBT build:

libraryDependencies += "io.higherkindness" %% "droste-core" % "x.y.z"

Usage

Droste makes it easy to assemble morphisms. For example, calculating Fibonacci values can be done with a histomorphism if we model natural numbers as a chain of Option. We can easily unfold with an anamorphism and then fold to our result with a histomorphism.

import higherkindness.droste._
import higherkindness.droste.data._

val natCoalgebra: Coalgebra[Option, BigDecimal] =
  Coalgebra(n => if (n > 0) Some(n - 1) else None)

val fibAlgebra: CVAlgebra[Option, BigDecimal] = CVAlgebra {
  case Some(r1 :< Some(r2 :< _)) => r1 + r2
  case Some(_ :< None)           => 1
  case None                      => 0
}

val fib: BigDecimal => BigDecimal = scheme.ghylo(
  fibAlgebra.gather(Gather.histo),
  natCoalgebra.scatter(Scatter.ana))
fib(0)
// res0: BigDecimal = 0
fib(1)
// res1: BigDecimal = 1
fib(2)
// res2: BigDecimal = 1
fib(10)
// res3: BigDecimal = 55
fib(100)
// res4: BigDecimal = 354224848179261915075

An anamorphism followed by a histomorphism is also known as a dynamorphism. Recursion scheme animals like dyna are available in the zoo:

val fibAlt: BigDecimal => BigDecimal =
  scheme.zoo.dyna(fibAlgebra, natCoalgebra)
fibAlt(0)
// res5: BigDecimal = 0
fibAlt(1)
// res6: BigDecimal = 1
fibAlt(2)
// res7: BigDecimal = 1
fibAlt(10)
// res8: BigDecimal = 55
fibAlt(100)
// res9: BigDecimal = 354224848179261915075

What if we want to do two things at once? Let's calculate a Fibonacci value and the sum of all squares.

val fromNatAlgebra: Algebra[Option, BigDecimal] = Algebra {
  case Some(n) => n + 1
  case None    => 0
}

// note: n is the fromNatAlgebra helper value from the previous level of recursion
val sumSquaresAlgebra: RAlgebra[BigDecimal, Option, BigDecimal] = RAlgebra {
  case Some((n, value)) => value + (n + 1) * (n + 1)
  case None             => 0
}

val sumSquares: BigDecimal => BigDecimal = scheme.ghylo(
  sumSquaresAlgebra.gather(Gather.zygo(fromNatAlgebra)),
  natCoalgebra.scatter(Scatter.ana))
sumSquares(0)
// res10: BigDecimal = 0
sumSquares(1)
// res11: BigDecimal = 1
sumSquares(2)
// res12: BigDecimal = 5
sumSquares(10)
// res13: BigDecimal = 385
sumSquares(100)
// res14: BigDecimal = 338350

Now we can zip the two algebras into one so that we calculate both results in one pass.

val fused: BigDecimal => (BigDecimal, BigDecimal) =
  scheme.ghylo(
    fibAlgebra.gather(Gather.histo) zip
    sumSquaresAlgebra.gather(Gather.zygo(fromNatAlgebra)),
    natCoalgebra.scatter(Scatter.ana))
fused(0)
// res15: (BigDecimal, BigDecimal) = (0, 0)
fused(1)
// res16: (BigDecimal, BigDecimal) = (1, 1)
fused(2)
// res17: (BigDecimal, BigDecimal) = (1, 5)
fused(10)
// res18: (BigDecimal, BigDecimal) = (55, 385)
fused(100)
// res19: (BigDecimal, BigDecimal) = (354224848179261915075, 338350)

Droste includes athema, a math expression parser/processor, as a more extensive example of recursion schemes.

Credits

A substantial amount of Droste's code is a derivation-- or an alternative encoding-- of patterns pioneered by others. Droste has benefited from the excellent work in many other recursion libraries, blog posts, academic papers, etc. Notably, Droste has benefited from:

Thank you to everyone involved. Additionally, thanks to Greg Pfeil (@sellout) for answering my random questions over the last few years while I've been slowly learning (and using recursion) schemes.

Copyright and License

Copyright the maintainers, 2018-present.

All code is available to you under the Apache License, Version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0.

Logos provided by the very excellent @impurepics.

Disclamer

Please be advised that I have no idea what I am doing. Nevertheless, this project is already being used for real work with real data in real life.

More Repositories

1

mu-haskell

Mu (ΞΌ) is a purely functional framework for building micro services.
Haskell
333
star
2

mu-scala

Mu is a purely functional library for building RPC endpoint based services with support for RPC and HTTP/2
Scala
332
star
3

skeuomorph

skema morphisms
Scala
89
star
4

rules_scala

Robust and featureful Bazel rules for Scala
Starlark
66
star
5

mu-graphql-example-elm

Complete full-stack web app with a mu-haskell GraphQL server and an Elm client! 🌳
Elm
37
star
6

compendium

HTTP service for schema storage and client generation
Scala
28
star
7

mu-kt

Mu - Purely Functional Microservices for Kotlin
Kotlin
17
star
8

avro-parser-haskell

Language definition and parser for AVRO (.avdl) files.
Haskell
16
star
9

sbt-mu-srcgen

Generate sources from IDL specifications
Scala
10
star
10

http2-grpc-haskell

gRPC over HTTP/2 for Haskell, client and server
Haskell
9
star
11

protobuf-parser-haskell

Parser for Protocol Buffers 3 files
Haskell
8
star
12

mu-scala-examples

mu-scala examples about https://github.com/higherkindness/mu-scala
Scala
7
star
13

higherkindness.github.io

The higherkindness.io website
SCSS
4
star
14

ersatz

Recursion schemes with Higherkindness talk
Scala
4
star
15

mu-graphql-example-reason

A ReasonML client example for our mu-haskell GraphQL server!
Reason
3
star
16

sbt-categorical-scalac

A plugin to configure opinionated Scala compiler options
Scala
3
star
17

mu-idea-plugin

Allows IntelliJ IDEA to peek on Mu macro-generated services - https://github.com/higherkindness/mu
Scala
3
star
18

compendium-example

It's a end-to-end example for compendium/sbt-compendium
Scala
3
star
19

mu-scala.g8

giter8 template for mu-scala applications
Scala
2
star
20

mu-protocol-decimal-update

Sample repository for showing how to upgrade a protocol with decimals in a safe way
Scala
2
star
21

mu-scala-haskell-integration-tests

Mu-Scala/Mu-Haskell nightly integration tests
Shell
2
star
22

sbt-compendium

SBT integration with compendium
Scala
1
star
23

protobluff

Scala
1
star
24

mu-server.g8

Giter8 template for a Mu server
Scala
1
star