hmemcpy / monadic-reflection

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Monadic Reflection

This project provides support for monadic reflection (Filinski 1994, 1999) to integrate monadic code with direct style code.

Tired of writing code using for-comprehensions?

The monadic-reflection library provides a convenient alternative!

Before

for {
  _ <- monadicActionA()
  r <- monadicActionB()
  result <- if (predicate(r)) {
    monadicActionC()
  } else {
    monadicActionD()
  }
} yield result

After

effectfulActionA()
if (predicate(effectfulActionB())) {
  effectfulActionC()
} else {
  effectfulActionD()
}

Looks familiar? Yes, it is just the direct-style code you would write in an imperative programming language.

Concepts

The underlying idea is very simple: Instead of using your monadic type constructor M[A] everywhere, your effectful programs now have the type CanReflect[M] ?=> A where CanReflect is a type defined by the monadic-reflection library.

As you can see from the type, given the capability CanReflect[M] you immediately get a value of type A that you can just use in direct-style. No need for flatMap and friends.

The best thing is, that you can go back and forth between the two representations:

trait Monadic[M[_]] {
  // embed a monadic value into direct style
  def reflect[R](mr: M[R])(using r: CanReflect[M]): R = r.reflect(mr)

  // reveal the monadic structure of a direct-style program
  def reify[R](prog: CanReflect[M] ?=> R): M[R]
}

How can I use this with my monad?

All you need to do is implement the Monadic trait which has two abstract methods:

def pure[A](a: A): M[A]
def sequence[X, R](init: M[X])(f: X => Either[M[X], M[R]]): M[R]

The first should look very familiar to you -- and if you already have a monad is very easy to implement. The second is just a slight variation of flatMap. In order to be stack safe you need to make sure to either implement sequence as a tail recursive function, or perform trampolining on your own.

Well, there is a fineprint: You also need to run your programs using a special JDK fork called "Project Loom". See below for more details.

Example Integrations

We provide a few case studies showing how to program with established monadic libraries in direct style:

Dependencies

To implement monadic reflection we require some implementation of (delimited) continuations. At the moment, our library only runs on a open JDK fork called project loom with runtime support for coroutines / delimited continuations.

Download a Loom-enabled JDK

There are early-access builds available at https://jdk.java.net/loom/.

Build Loom

To build the custom JVM yourself, clone the repository

git clone https://github.com/openjdk/loom

and checkout the continuation branch cont:

git checkout fibers

Detailed instructions on how to build the JDK can be found in the file doc/building.md, in short those are:

bash configure
make images

Run Sbt

Finally, run sbt with the newly built JVM. Assuming you checked out loom into PATH and built on a mac, run:

sbt -java-home $PATH/build/macosx-x86_64-server-release/images/jdk

Obviously the path needs to be adjusted for other operating systems.

Some experimental performance optimizations of project loom can be enabled by

-XX:-DetectLocksInCompiledFrames -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseNewCode

About


Languages

Language:Scala 100.0%