Code Monkey home page Code Monkey logo

magic-mirror's Introduction

magic-mirror

Implementation of Generic, Lens, and HKD in Dotty

Download

Usage

You should add the following to your build.sbt.

resolvers += Resolver.jcenterRepo

libraryDependencies += "com.phenan" %% "magic-mirror" % "0.9.4"

This library is developped on Dotty version 0.22.0-RC1.

Generic

Generic is a type class that expresses interconversion between algebraic data type and simple data type expressed with product and union. It is useful for various situation. For example, we can easily implement serializer and deserializer with Generic because we can construct and destruct different data types in the same fashion.

In Scala2, shapeless provides implementation of Generic. Generic in shapeless is implemented by macros, and the deconstructed data type is expressed by HList and Coproduct. This is also useful, however, HList and Coproduct are not common in Scala, so it is not convenient for normal users.

magic-mirror provides Generic that is based on Mirror. Mirror is a reflection API in Dotty. The deconstructed data type of Generic in magic-mirror is expressed by Tuple and Union. Both Tuple and Union is standard data type in Dotty, so programmers can easily to use it. magic-mirror also support Generic with Coproduct instead of Union because Coproduct is more powerful than Union. In fact, we can convert any Coproduct into Union but cannot convert Union into Coproduct.

Sample

sealed trait Foo
case class Bar (a: Int, b: String) extends Foo
case class Baz (c: String) extends Foo

import com.phenan.generic.{given _, _}
import com.phenan.util._

val generic1 = summon[ProductGeneric[Bar, (Int, String)]]

val a: Bar = generic1.fromUnderlying((10, "bar"))     // Bar(10, "bar")
val b: (Int, String) = generic1.toUnderlying(a)       // (10, "bar")

val generic2 = summon[UnionGeneric[Foo, (Bar, Baz)]]

val c: Bar | Baz = generic2.toUnderlying(Baz("baz"))  // Baz("baz") : Bar | Baz
val d: Foo = generic2.fromUnderlying(c)               // Baz("baz") : Foo

val generic3 = summon[CoproductGeneric[Foo, (Bar, Baz)]]

val e: Bar |: Baz |: CNil = generic3.toUnderlying(Baz("baz"))
val f: Foo = generic3.fromUnderlying(e)

Lens

magic-mirror also support Lens. Lens is a type class expressing getter and setter of a field of a data object.

This library provides Lens for any field of case classes by utilizing Mirror.

If you want to get Lens for field x of algebraic data type Foo, you should simply call MirrorLens[Foo].x. You can also get Lens of nested object with this dot-notation. For example, MirrorLens[Foo].bar.baz returns Lens[Foo, Baz] for the following definition.

case class Foo (bar: Bar, x: Int)
case class Bar (baz: baz)
case class Baz (n: Int, s: String)

Sample

case class Foo (a: Int, b: String, c: Int)

import com.phenan.lens._
import com.phenan.lens.{given _}
import com.phenan.util.{given _}

val aLens = MirrorLens[Foo].a

println(aLens.get(Foo(1, "foo", 2)))     // 1
println(aLens.set(Foo(1, "foo", 2))(5))  // Foo(5, "foo", 2)

// println(aLens.set(Foo(1, "foo", 2))("foo"))  // compile error!
// val dLens = MirrorLens[Foo].d                // compile error!

HKD

Higher-kinded data (HKD) is a data type that is parameterized by something of kind * -> *. For example, HKD[Foo, Option] expresses a data type that wraps data type Foo, and all fields are wrapped by Option. The fields of HKD[Foo, Option] can be accessed by regular syntax of field access, such as hkd.bar. The fields of HKD[Foo, Option] is mutable and we can also use assignment syntax. We can easily translate HKD[Foo, Option] into Option[Foo] by simply call build method.

Sample

import com.phenan.hkd.{given _, _}
import com.phenan.lens.{given _}
import com.phenan.std.{given _}
import com.phenan.util.{given _}

case class Foo (a: Int, b: String)

val hkd = HKD[Foo, Option](Some(10), None)
// val hkd2 = HKD[Foo, Option](Some("hoge"), Some(10))   // compile error!

val x = hkd.a        // Some(10)
val y = hkd.b        // None
// val z = hkd.c     // compile error!

hkd.a = Some(20)
hkd.b = Some("bar")
// hkd.b = Some(10)  // compile error!

val fooOpt: Option[Foo] = hkd.build   // Some(Foo(20, "bar"))

Author

@phenan

magic-mirror's People

Contributors

phenan avatar

Stargazers

 avatar TATSUNO “Taz” Yasuhiro avatar Hiroshi YAMAGUCHI avatar

Watchers

 avatar

Forkers

hurou927

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.