ProductPromotion
Logo

Scala

made by https://0x3d.site

GitHub - Thangiee/Freasy-Monad: Easy way to create Free Monad using Scala macros with first-class Intellij support.
Easy way to create Free Monad using Scala macros with first-class Intellij support. - Thangiee/Freasy-Monad
Visit Site

GitHub - Thangiee/Freasy-Monad: Easy way to create Free Monad using Scala macros with first-class Intellij support.

GitHub - Thangiee/Freasy-Monad: Easy way to create Free Monad using Scala macros with first-class Intellij support.

Freasy Monad

Freasy Monad library makes it easy to create Free Monad for typelevel/cats and scalaz/scalaz.

Getting started

Important

  • Version 0.6.0 uses scala.meta. If using IntelliJ, please uninstall the Freasy Monad Plugin if you have it installed.

  • Replace addCompilerPlugin("org.scalamacros" % "paradise" % "2.1.0" cross CrossVersion.full) with addCompilerPlugin("org.scalameta" % "paradise" % "3.0.0-M11" cross CrossVersion.full) for those coming from versions before 0.6.0.

Freasy Monad is currently available for Scala 2.11 and 2.12, and Scala.js.

If you are using cats, add the following to your build.sbt:

libraryDependencies ++= Seq(
  "com.github.thangiee" %% "freasy-monad" % "0.7.0",
  "org.typelevel" %% "cats-free" % "1.1.0"
)
addCompilerPlugin("org.scalameta" % "paradise" % "3.0.0-M11" cross CrossVersion.full)

If you are using scalaz, add the following to your build.sbt:

libraryDependencies ++= Seq(
  "com.github.thangiee" %% "freasy-monad" % "0.7.0",
  "org.scalaz" %% "scalaz-core" % "7.2.22"
)
addCompilerPlugin("org.scalameta" % "paradise" % "3.0.0-M11" cross CrossVersion.full)

Starting with version 0.5.0, group ID has been changed from com.thangiee to com.github.thangiee.

@free macro

Key-value store example from cats website using free macro:

  import cats._
  import cats.free._
  import freasymonad.cats.free // or freasymonad.scalaz.free
  import scala.collection.mutable

  @free trait KVStore {                     // you can use any names you like
    type KVStoreF[A] = Free[GrammarADT, A]  // as long as you define a type alias for Free 
    sealed trait GrammarADT[A]              // and a sealed trait.

    // abstract methods are automatically lifted into part of the grammar ADT
    def put[T](key: String, value: T): KVStoreF[Unit]
    def get[T](key: String): KVStoreF[Option[T]]

    def update[T](key: String, f: T => T): KVStoreF[Unit] =
      for {
        vMaybe <- get[T](key)
        _      <- vMaybe.map(v => put[T](key, f(v))).getOrElse(Free.pure(()))
      } yield ()
  }

  object Main extends App {
    import KVStore.ops._
  
    def program: KVStoreF[Option[Int]] =
      for {
        _ <- put("wild-cats", 2)
        _ <- update[Int]("wild-cats", _ + 12)
        _ <- put("tame-cats", 5)
        n <- get[Int]("wild-cats")
      } yield n
  
    val impureInterpreter = new KVStore.Interp[Id] {
      val kvs = mutable.Map.empty[String, Any]
      def get[T](key: String): Id[Option[T]] = {
        println(s"get($key)")
        kvs.get(key).map(_.asInstanceOf[T])
      }
      def put[T](key: String, value: T): Id[Unit] = {
        println(s"put($key, $value)")
        kvs(key) = value
      }
    }
    
    impureInterpreter.run(program)
  }

Above example for scalaz here.

During compile time, KVStore is expanded to something similar to:

  object KVStore {
    import cats._
    import cats.free._
    import scala.language.higherKinds
    sealed trait GrammarADT[A]
    object GrammarADT {
      case class Put[T](key: String, value: T) extends GrammarADT[Unit]
      case class Get[T](key: String) extends GrammarADT[Option[T]]
    }
    object ops {
      type KVStoreF[A] = Free[GrammarADT, A]
      def put[T](key: String, value: T): KVStoreF[Unit] = injectOps.put[GrammarADT, T](key, value)
      def get[T](key: String): KVStoreF[Option[T]] = injectOps.get[GrammarADT, T](key)
      def update[T](key: String, f: T => T): KVStoreF[Unit] = injectOps.update[GrammarADT, T](key, f) 
    }
    object injectOps {
      def put[F[_], T](key: String, value: T)(implicit I: Inject[GrammarADT, F]): Free[F, Unit] = Free.liftF(I.inj(GrammarADT.Put(key, value)));
      def get[F[_], T](key: String)(implicit I: Inject[GrammarADT, F]): Free[F, Option[T]] = Free.liftF(I.inj(GrammarADT.Get(key)));
      def update[F[_], T](key: String, f: T => T)(implicit I: Inject[GrammarADT, F]): Free[F, Unit] =
        for {
          vMaybe <- get[F, T](key)
          _      <- vMaybe.map(v => put[F, T](key, f(v))).getOrElse(Free.pure(()))
        } yield ()
    }
    class Injects[F[_]](implicit I: Inject[GrammarADT, F]) {
      def put[T](key: String, value: T): Free[F, Unit] = injectOps.put[F, T](key, value);
      def get[T](key: String): Free[F, Option[T]] = injectOps.get[F, T](key);
      def update[T](key: String, f: T => T): Free[F, Unit] = injectOps.update[F, T](key, f)
    }
    object Injects {
      implicit def injectOps[F[_]](implicit I: Inject[GrammarADT, F]): Inject[F] = new Inject[F]()
    }
    trait Interp[M[_]] extends ~>[KVStore.GrammarADT, M] {
      def apply[A](fa: KVStore.GrammarADT[A]): M[A] = fa match {
        case GrammarADT.Put(key, value) => put(key, value)
        case GrammarADT.Get(key) => get(key)
      }
      def run[A](op: KVStore.ops.KVStoreF[A])(implicit m: cats.Monad[M]): M[A] = op.foldMap(this)
      def put[T](key: String, value: T): M[Unit]
      def get[T](key: String): M[Option[T]]
    }
  }

Benefits

  • From the expanded version, we can see that the free macro takes care most of the tedious parts when it comes to writing free monad. The macro uses our abstract methods to define the ADT case classes, create smart constructors to case classes, and do pattern matching on the ADT.

  • This library also generate Inject for composing Free monads ADTs. See example for cats and scalaz.

  • Writing an interpreter using Intellij becomes a breeze:

    impl

  • No more false error marks when writing interpreter with Intellij!

    regular-interp freasy-monad-interp

IntelliJ support

Since switch to scala.meta in version 0.6.0, syntax highlighting & code completion in IntelliJ works without needing to install a plugin. Therefore, the Freasy Monad Plugin needs to be uninstalled if you are coming from a previous version.

Constraints

There are some constraints on @free trait, and if violated, will result in a compiler error.

  • Can not define var.
  • All val and def need to have an explicit return type.
  • Abstract val and def must have a return type of the defined type alias. From the example above, this would be KVStoreF[...].
  • private and protected access modifiers are not allowed, use package-private instead.

More Resources
to explore the angular.

mail [email protected] to add your project or resources here 🔥.

Related Articles
to learn about angular.

FAQ's
to learn more about Angular JS.

mail [email protected] to add more queries here 🔍.

More Sites
to check out once you're finished browsing here.

0x3d
https://www.0x3d.site/
0x3d is designed for aggregating information.
NodeJS
https://nodejs.0x3d.site/
NodeJS Online Directory
Cross Platform
https://cross-platform.0x3d.site/
Cross Platform Online Directory
Open Source
https://open-source.0x3d.site/
Open Source Online Directory
Analytics
https://analytics.0x3d.site/
Analytics Online Directory
JavaScript
https://javascript.0x3d.site/
JavaScript Online Directory
GoLang
https://golang.0x3d.site/
GoLang Online Directory
Python
https://python.0x3d.site/
Python Online Directory
Swift
https://swift.0x3d.site/
Swift Online Directory
Rust
https://rust.0x3d.site/
Rust Online Directory
Scala
https://scala.0x3d.site/
Scala Online Directory
Ruby
https://ruby.0x3d.site/
Ruby Online Directory
Clojure
https://clojure.0x3d.site/
Clojure Online Directory
Elixir
https://elixir.0x3d.site/
Elixir Online Directory
Elm
https://elm.0x3d.site/
Elm Online Directory
Lua
https://lua.0x3d.site/
Lua Online Directory
C Programming
https://c-programming.0x3d.site/
C Programming Online Directory
C++ Programming
https://cpp-programming.0x3d.site/
C++ Programming Online Directory
R Programming
https://r-programming.0x3d.site/
R Programming Online Directory
Perl
https://perl.0x3d.site/
Perl Online Directory
Java
https://java.0x3d.site/
Java Online Directory
Kotlin
https://kotlin.0x3d.site/
Kotlin Online Directory
PHP
https://php.0x3d.site/
PHP Online Directory
React JS
https://react.0x3d.site/
React JS Online Directory
Angular
https://angular.0x3d.site/
Angular JS Online Directory