I am studying Scala and trying to implement some abstractions for custom types. Defining scalaz monoids for concrete classes is quite straightforward. But how to declare one Monoid for the type hierarchy? Assuming this code:
sealed trait Base
case class A(v:Int) extends Base
object N extends Base
object Main {
// Wanna one monoid for all the Base's
implicit val baseMonoid = new Monoid[Base] {
override def append(f1: Base, f2: => Base): Base = f1 match {
case A(x) => f2 match {
case A(y) => A(x + y)
case N => A(x)
}
case N => f2
}
override def zero = N
}
def main(args: Array[String]): Unit = {
println(∅[Base] |+| A(3) |+| A(2)) // Compiles
println(A(3) |+| A(2)) // Not compiles
}
}
How to make state A() |+| B() workable in the example above?
This compiles:
import scalaz._, Scalaz._
sealed trait Base
case class A(a: Int) extends Base
case class B(b: Int) extends Base
object N extends Base
object BullShit {
// Wanna one monoid for all the Base's
implicit val sg: Semigroup[Base] = new Semigroup[Base] {
override def append(f1: Base, f2: => Base): Base = f1 match {
case A(a) => f2 match {
case A(a1) => A(a + a1)
case B(b) => A(a + b)
case N => N
}
case B(b) => f2 match {
case A(a) => B(a + b)
case B(b1) => B(b + b1)
case N => N
}
case N => f2
}
}
println((A(1): Base) |+| (B(2): Base))
}
And your example would compile if you tell Scala's horrible type inferencer what you mean:
sealed trait Base
case class A(v: Int) extends Base
object N extends Base
object Main {
// Wanna one monoid for all the Base's
implicit val baseMonoid = new Monoid[Base] {
override def append(f1: Base, f2: => Base): Base = f1 match {
case A(x) => f2 match {
case A(y) => A(x + y)
case N => A(x)
}
case N => f2
}
override def zero = N
}
def main(args: Array[String]): Unit = {
import scalaz._, Scalaz._
println(∅[Base] |+| A(3) |+| A(2)) // Compiles
println((A(3): Base) |+| (A(2): Base)) // now it compiles
}
}
Related
I'm trying to write a value class that wraps Scala collection's Map and provides an alternative get. I'm trying to use a phantom type in the value class and tag the Key with the same type using the method member. If the result of member is Some(k) then the user should be able to call get(k) and get a V instead of an Option[V].
import scala.collection.{Map => M}
class Key[PH, K] private (val k: K) extends AnyVal
object Key {
def apply[PH, K](k: K): Key[PH, K] = new Key(k)
}
class Map[PH, K, V] private (val m: M[K, V]) extends AnyVal {
def member(k: K): Option[Key[PH, K]] = m.get(k).map(_ => Key(k))
def get(key: Key[PH, K]): V = m.get(key.k).get
}
object Map {
def apply[PH, K, V](m: M[K, V]): Map[PH, K, V] = new Map(m)
}
def withMap[K, V, T](m: M[K, V])(cont: (Map[PH, K, V] forSome { type PH }) => T): T = cont(Map(m))
withMap(M("a" -> "a")){ m =>
m.member("a") match {
case Some(v) => println(m.get(v))
case None => println(":(")
}
}
But currently it fails compiling with the following error:
found : Key[PH(in value $anonfun),String] where type +PH(in value $anonfun)
required: Key[PH(in value cont),String]
case Some(v) => println(m.get(v))
How can I convince scalac that the PHs are the same?
Destructure the existential:
withMap(M("a" -> "a")) { case m =>
m.member("a") match {
case Some(v) => println(m.get(v))
case None => println(":(")
}
}
This abbreviates
withMap(M("a" -> "a")) { case m: Map[ph, String, String] => // name the phantom type ph, name the map m =>
m.member("a") match {
case Some(v) => println(m.get(v))
case None => println(":(")
}
}
The destructuring allows m to be given a non-existential type in terms of a newly introduced type variable. This means that every occurrence of m can now have the same type.
Phantom types are meaningless. You should say what you mean: every Key belongs to a certain Map:
import scala.collection.immutable.Map // it is not safe to use Maps in general!
class KeyedMap[K, V](val m: Map[K, V]) extends AnyVal {
import KeyedMap._
def member(k: K): Option[Key[K, V, m.type]] = m.get(k).map { _ => new Key[K, V, m.type](k) }
def fromKey(k: Key[K, V, m.type]): V = m(k.k)
}
object KeyedMap {
// vvvvvvvvvvvvvv requires this parameter to be <something>.type
class Key[K, +V, M <: Map[K, V] with Singleton] private[KeyedMap](val k: K) extends AnyVal
}
object Test {
def main(args: String*): Unit = {
val m = new KeyedMap(Map("a" -> "b"))
m.member("a") match {
case Some(v) => println(m.fromKey(v))
case None => println(":(")
}
}
}
I've been doing an exercise to try to implement a basic Calculator with Free Monad.
As I understand the intention of the Free Monad and what I wanted to achieve is:
write my program (math expression) once run it with different interpreters.
Now i am not sure that I did the 100% idiomatic implementation at least because:
My program kinda needs to be parametrized on the generic type A which should match the interpreter context.
def program[A] = for {
two <- lit[A](2)
four <- lit[A](4)
sum <- add(two, four)
} yield sum
program[Int].foldMap(eval) shouldBe 6
program[String].foldMap(print) shouldBe "(2 + 4)"
import cats.instances.option._
program[Option[Int]].foldMap(evalOpt) shouldBe Option(6)
The ADT/algebra and 'smart constructors'
trait Expression2[A] extends Product with Serializable
case class Lit[A](a: Int) extends Expression2[A]
case class Add[A](a: A, b: A) extends Expression2[A]
case class Mult[A](a: A, b: A) extends Expression2[A]
type ExprAlg[B] = Free[Expression2, B]
def lit[A](a: Int): ExprAlg[A] = Free.liftF(Lit(a))
def add[A](a: A, b: A): ExprAlg[A] = Free.liftF(Add(a, b))
def mult[A](a: A, b: A): ExprAlg[A] = Free.liftF(Mult(a, b))
The math interpreter:
def eval: Expression2 ~> Id = new (Expression2 ~> Id) {
override def apply[A](fa: Expression2[A]): Id[A] = eval(fa).asInstanceOf[A]
def eval[A](expression2: Expression2[A]): Int = expression2 match {
case Lit(n) => n
case Add(a, b) => a.asInstanceOf[Int] + b.asInstanceOf[Int]
case Mult(a, b) => a.asInstanceOf[Int] * b.asInstanceOf[Int]
}
}
The print interpreter:
def print: Expression2 ~> Id = new (Expression2 ~> Id) {
override def apply[A](fa: Expression2[A]): Id[A] = eval(fa).asInstanceOf[A]
def eval[A](expression2: Expression2[A]): String = expression2 match {
case Lit(n) => n.toString
case Add(a, b) => "(" + a.toString + " + " + b.toString + ")"
case Mult(a, b) => "(" + a.toString + " * " + b.toString + ")"
}
}
The math in Option interpreter:
def evalOpt: Expression2 ~> Option = new (Expression2 ~> Option) {
override def apply[A](fa: Expression2[A]): Option[A] = eval(fa).map{_.asInstanceOf[A]}
def eval[A](expression2: Expression2[A]): Option[Int] = expression2 match {
case Lit(n) => Option(n)
case Add(a, b) => Option(a.asInstanceOf[Int] + b.asInstanceOf[Int])
case Mult(a, b) => Option(a.asInstanceOf[Int] * b.asInstanceOf[Int])
}
}
Related to the Option interpreter, I would have expected that the a and b vars to be option, and in the string interpreter a and b to be strings because of my the ADT result type is A: Expression2[A].
I also tried instead of Lit[A](a: Int), to have Lit[A](a: A) but then it breaks down: i cannot pass different interpreters for the same expression when A is fixed to an Int in my program and I expect not to have to rewrite my program for different interpreters.
So a couple things. Generally you reaaaally want to avoid asInstanceOf because right now you can construct an Expression2 with any type and then it'd just crash on evaluating because it's not actually an Int. There's a couple ways to mitigate this. You can either just fix the type of the contained numeric type in your Expression2
import scalaz._
import Scalaz._
trait Expression2[A] extends Product with Serializable
case class Lit[A](a: Int) extends Expression2[Int]
case class Add[A](a: Int, b: Int) extends Expression2[Int]
case class Mult[A](a: Int, b: Int) extends Expression2[Int]
type ExprAlg[A] = Free[Expression2, A]
def lit(a: Int): ExprAlg[Int] = Free.liftF(Lit(a))
def add(a: Int, b: Int): ExprAlg[Int] = Free.liftF(Add(a, b))
def mult(a: Int, b: Int): ExprAlg[Int] = Free.liftF(Mult(a, b))
val eval: Expression2 ~> Id = new (Expression2 ~> Id) {
override def apply[A](fa: Expression2[A]): Id[A] = eval(fa)
def eval[A](expression2: Expression2[A]): A = expression2 match {
case Lit(n) => n
case Add(a, b) => a+b
case Mult(a, b) => a*b
}
}
Or you can associate the capability with the operations like this. basically you can think of the cases in your ADT like Add like this: The parameters of the case class are like function parameters and the type you put into the Extends is the result type.
import scalaz._
import Scalaz._
import spire.algebra._
import spire.implicits._
trait Expression2[A] extends Product with Serializable
case class Lit[A](a: A) extends Expression2[A]
case class Add[A](a: A, b: A)(implicit val ev:Semiring[A]) extends Expression2[A]
case class Mult[A](a: A, b: A)(implicit val ev:Semiring[A]) extends Expression2[A]
type ExprAlg[A] = Free[Expression2, A]
def lit[A](a: A): ExprAlg[A] = Free.liftF(Lit(a))
def add[A](a: A, b: A)(implicit ev:Semiring[A]): ExprAlg[A] = Free.liftF(Add(a, b))
def mult[A](a: A, b: A)(implicit ev:Semiring[A]): ExprAlg[A] = Free.liftF(Mult(a, b))
val eval: Expression2 ~> Id = new (Expression2 ~> Id) {
override def apply[A](fa: Expression2[A]): Id[A] = eval(fa)
def eval[A](expression2: Expression2[A]): Id[A] = expression2 match {
case Lit(n) => n
case x:Add[A] => x.ev.plus(x.a,x.b)
case x:Mult[A] => x.ev.times(x.a,x.b)
}
}
def program[A: Semiring](a:A,b:A) = for {
two <- lit(a)
four <- lit(b)
sum <- add(two, four)
} yield sum
println(program[Int](2,4).foldMap(eval) )
Now as for your Option case I am not quite sure why you want to interpret into an Option here. if you can do F ~> Id for some F, F ~> Option really is just Some applied to the first natural transformation.
I would like to define a State that builds a concrete subtype of a trait, as per decodeFoo:
sealed trait Foo
case class Bar(s: String) extends Foo
case class Baz(i: Int) extends Foo
val int: State[Seq[Byte], Int] = State[Seq[Byte], Int] {
case bs if bs.length >= 4 =>
bs.drop(4) -> ByteBuffer.wrap(bs.take(4).toArray).getInt
case _ => sys.error(s"Insufficient data remains to parse int")
}
def bytes(len: Int): State[Seq[Byte], Seq[Byte]] = State[Seq[Byte], Seq[Byte]] {
case bs if bs.length >= len => bs.drop(len) -> bs.take(len)
case _ => sys.error(s"Insufficient data remains to parse $len bytes")
}
val bytes: State[Seq[Byte], Seq[Byte]] = for {
len <- int
bs <- bytes(len)
} yield bs
val string: State[Seq[Byte], String] = bytes.map(_.toArray).map(new String(_, Charset.forName("UTF-8")))
val decodeBar: State[Seq[Byte], Bar] = string.map(Bar)
val decodeBaz: State[Seq[Byte], Baz] = int.map(Baz)
val decodeFoo: State[Seq[Byte], Foo] = int.flatMap {
case 0 => decodeBar
case 1 => decodeBaz
}
This will not compile as State is defined in cats as type State[S, A] and the compiler responds:
Error:(36, 15) type mismatch;
found : cats.data.State[Seq[Byte],FooBarBaz.this.Bar]
(which expands to) cats.data.IndexedStateT[cats.Eval,Seq[Byte],Seq[Byte],FooBarBaz.this.Bar]
required: cats.data.IndexedStateT[cats.Eval,Seq[Byte],Seq[Byte],FooBarBaz.this.Foo]
Note: FooBarBaz.this.Bar <: FooBarBaz.this.Foo, but class IndexedStateT is invariant in type A.
You may wish to define A as +A instead. (SLS 4.5)
case 0 => decodeBar
I can work around this by widening the definitions of decodeBar & decodeBaz to be of type State[Seq[Byte], Foo]. Is that the best way forward? Or can I take a different approach that avoids widening these types?
Functor.widen
Functor.widen should do the trick. Full compilable example (with kind-projector):
import cats.data.State
import cats.Functor
object FunctorWidenExample {
locally {
sealed trait A
case class B() extends A
val s: State[Unit, B] = State.pure(new B())
val t: State[Unit, A] = Functor[State[Unit, ?]].widen[B, A](s)
}
}
in your case, it would be something like:
val decodeFoo: State[Seq[Byte], Foo] = int.flatMap {
case 0 => Functor[State[Seq[Byte], ?]].widen[Bar, Foo](decodeBar)
case 1 => Functor[State[Seq[Byte], ?]].widen[Bar, Foo](decodeBaz)
}
Other possible work-arounds
(not really necessary, just to demonstrate the syntax that might be less known):
Explicit type ascriptions:
val decodeFoo: State[Seq[Byte], Foo] = int.flatMap {
case 0 => decodeBar.map(x => (x: Foo))
case 1 => decodeBaz.map(x => (x: Foo))
}
Using <:< as method (those things actually do have a meaningful apply):
val decodeFoo: State[Seq[Byte], Foo] = int.flatMap {
case 0 => decodeBar.map(implicitly: Bar <:< Foo)
case 1 => decodeBaz.map(implicitly: Baz <:< Foo)
}
It is not fully clear to me what is the purpose of the emptyCoProduct and coproduct methods of the TypeClass trait in Shapeless.
When would one use the TypeClass trait instead of the ProductTypeClass?
What are some examples of ways those two methods would be implemented?
Suppose I've got a simple type class:
trait Weight[A] { def apply(a: A): Int }
object Weight {
def apply[A](f: A => Int) = new Weight[A] { def apply(a: A) = f(a) }
}
And some instances:
implicit val stringWeight: Weight[String] = Weight(_.size)
implicit def intWeight: Weight[Int] = Weight(identity)
And a case class:
case class Foo(i: Int, s: String)
And an ADT:
sealed trait Root
case class Bar(i: Int) extends Root
case class Baz(s: String) extends Root
I can define a ProductTypeClass instance for my type class:
import shapeless._
implicit object WeightTypeClass extends ProductTypeClass[Weight] {
def emptyProduct: Weight[HNil] = Weight(_ => 0)
def product[H, T <: HList](hw: Weight[H], tw: Weight[T]): Weight[H :: T] =
Weight { case (h :: t) => hw(h) + tw(t) }
def project[F, G](w: => Weight[G], to: F => G, from: G => F): Weight[F] =
Weight(f => w(to(f)))
}
And use it like this:
scala> object WeightHelper extends ProductTypeClassCompanion[Weight]
defined object WeightHelper
scala> import WeightHelper.auto._
import WeightHelper.auto._
scala> implicitly[Weight[Foo]]
res0: Weight[Foo] = Weight$$anon$1#4daf1b4d
scala> implicitly[Weight[Bar]]
res1: Weight[Bar] = Weight$$anon$1#1cb152bb
scala> implicitly[Weight[Baz]]
res2: Weight[Baz] = Weight$$anon$1#74930887
But!
scala> implicitly[Weight[Root]]
<console>:21: error: could not find implicit value for parameter e: Weight[Root]
implicitly[Weight[Root]]
^
This is a problem—it makes our automated type class instance derivation pretty much useless for ADTs. Fortunately we can use TypeClass instead:
implicit object WeightTypeClass extends TypeClass[Weight] {
def emptyProduct: Weight[HNil] = Weight(_ => 0)
def product[H, T <: HList](hw: Weight[H], tw: Weight[T]): Weight[H :: T] =
Weight { case (h :: t) => hw(h) + tw(t) }
def project[F, G](w: => Weight[G], to: F => G, from: G => F): Weight[F] =
Weight(f => w(to(f)))
def emptyCoproduct: Weight[CNil] = Weight(_ => 0)
def coproduct[L, R <: Coproduct]
(lw: => Weight[L], rw: => Weight[R]): Weight[L :+: R] = Weight {
case Inl(h) => lw(h)
case Inr(t) => rw(t)
}
}
And then:
scala> object WeightHelper extends TypeClassCompanion[Weight]
defined object WeightHelper
scala> import WeightHelper.auto._
import WeightHelper.auto._
scala> implicitly[Weight[Root]]
res0: Weight[Root] = Weight$$anon$1#7bc44e19
All the other stuff above still works as well.
To sum up: Shapeless's Coproduct is a kind of abstraction over ADTs, and in general you should provide instances of TypeClass for your type classes instead of just ProductTypeClass whenever possible.
As of shapeless 2.3.2, the above example doesn't seem to compile. here's the updated one for future reference:
import shapeless._
import shapeless.test._
trait Weight[A] { def apply(a: A): Int }
object Weight {
def apply[A](f: A => Int) = new Weight[A] { def apply(a: A) = f(a) }
}
case class Foo(i: Int, s: String)
sealed trait Root
case class Bar(i: Int) extends Root
case class Baz(s: String) extends Root
object Base {
implicit val stringWeight: Weight[String] = Weight(_.size)
implicit def intWeight: Weight[Int] = Weight(identity)
}
object ProductTC {
object WeightHelper extends ProductTypeClassCompanion[Weight] {
object typeClass extends ProductTypeClass[Weight] {
def emptyProduct: Weight[HNil] = Weight(_ => 0)
def product[H, T <: HList](hw: Weight[H], tw: Weight[T]): Weight[H :: T] =
Weight { case (h :: t) => hw(h) + tw(t) }
def project[F, G](w: => Weight[G], to: F => G,from: G => F): Weight[F] =
Weight(f => w(to(f)))
}
}
import Base._
import WeightHelper._
implicitly[Weight[Foo]]
implicitly[Weight[Bar]]
implicitly[Weight[Baz]]
illTyped("implicitly[Weight[Root]]")
}
object TC {
object WeightTypeClass extends TypeClassCompanion[Weight] {
object typeClass extends TypeClass[Weight] {
def emptyProduct: Weight[HNil] = Weight(_ => 0)
def product[H, T <: HList](hw: Weight[H], tw: Weight[T]): Weight[H :: T] =
Weight { case (h :: t) => hw(h) + tw(t) }
def project[F, G](w: => Weight[G], to: F => G, from: G => F): Weight[F] =
Weight(f => w(to(f)))
def emptyCoproduct: Weight[CNil] = Weight(_ => 0)
def coproduct[L, R <: Coproduct]
(lw: => Weight[L], rw: => Weight[R]): Weight[L :+: R] = Weight {
case Inl(h) => lw(h)
case Inr(t) => rw(t)
}
}
}
import Base._
import WeightTypeClass._
implicitly[Weight[Root]]
}
I have trouble with Scala traits and type erasure. I have this trait:
trait Meta[T] {
def ~=(e: T): Boolean
}
Now I want to use pattern matching to check for this case:
(m,i) match {
case (x:Meta[T], y: T) if x ~= y => println ("right")
case _ => println ("wrong")}
The T from x: Meta[T] should be the type of y or y should be a subtype of T.
If the types don't match I get an ClassCastException. But x ~= y should not be executed if the types are not correct. Is there a away around this or do I have to catch the exception and handle it that way?
I made an running example as short as possible:
trait Meta[T] {
type t = T
def ~=(e: T): Boolean
}
sealed abstract class A
case class Ide(s: String) extends A
case class MIde(s: String) extends A with Meta[A] {
def ~=(e: A) = e match {
case e: Ide => true
case e: MIde => false
}
}
sealed abstract class B
case class Foo(s: String) extends B
object Test {
def m = MIde("x")
def i = Ide("i")
def f = Foo("f")
def main[T](args: Array[String]) {
(m, i) match {
case (x: Meta[T], y: T) if x ~= y => println("right")
case _ => println("wrong")
}
// -> right
(m, f) match {
case (x: Meta[T], y: T) if x ~= y => println("right")
case _ => println("wrong")
}
// -> Exception in thread "main" java.lang.ClassCastException:
// Examples.Foo cannot be cast to Examples.A
}
}
UPDATE: added alternative at the end.
You are experiencing the limitations of pattern matching when it comes to generic types, due to type erasure.
All is not lost however. We can rely on ClassManifests to implement a generic method to convert your classes to a target type T (and another similar on to convert to Meta[T]):
trait Meta[T] { this: T =>
type t = T
def metaManifest: ClassManifest[T]
def ~=(e: T): Boolean
}
abstract sealed class Base {
def as[T:ClassManifest]: Option[T] = {
if ( classManifest[T].erasure.isAssignableFrom( this.getClass ) ) Some( this.asInstanceOf[T] )
else None
}
def asMeta[T:ClassManifest]: Option[T with Meta[T]] = {
this match {
case meta: Meta[_] if classManifest[T] <:< meta.metaManifest => as[T].asInstanceOf[Option[T with Meta[T]]]
case _ => None
}
}
}
abstract sealed class A extends Base
case class Ide(s: String) extends A
case class MIde(s: String) extends A with Meta[A] {
val metaManifest = classManifest[A]
def ~=(e: A) = e match {
case e: Ide => true
case e: MIde => false
}
}
sealed abstract class B extends Base
case class Foo(s: String) extends B
Let's test this in the REPL:
scala> m.as[A]
res17: Option[A] = Some(MIde(x))
scala> m.asMeta[A]
res18: Option[A with Meta[A]] = Some(MIde(x))
scala> i.as[A]
res19: Option[A] = Some(Ide(i))
scala> i.asMeta[A]
res20: Option[A with Meta[A]] = None
scala> f.as[A]
res21: Option[A] = None
scala> f.asMeta[A]
res22: Option[A with Meta[A]] = None
Sounds good. Now we can rewrite our pattern matching from this:
(m, i) match {
case (x: Meta[T], y: T) if x ~= y => println("right")
case _ => println("wrong")
}
to this:
(m.asMeta[T], i.as[T]) match {
case (Some(x), Some(y)) if x ~= y => println("right")
case _ => println("wrong")
}
So your example would now look like this:
object Test {
val m = MIde("x")
val i = Ide("i")
val f = Foo("f")
def test[T:ClassManifest]() {
(m.asMeta[T], i.as[T]) match {
case (Some(x), Some(y)) if x ~= y => println("right")
case _ => println("wrong")
}
// -> right
(m.asMeta[T], f.as[T]) match {
case (Some(x), Some(y)) if x ~= y => println("right")
case _ => println("wrong")
}
}
}
UPDATE: if setting explictly metaManifest everytime you mix Meta is not an option, you can let scala automtically infer it by passing it implictly in Metas constructor. This means that Meta must now be a class, and as a consequence A and B (and all similar types that must appear as Meta's type parameter) must now be traits, as you can't mix 2 classes. So you are basically swapping a restriction for another one. Choose your favorite one.
Here we go:
abstract sealed class Meta[T]( implicit val metaManifest: ClassManifest[T] ) { this: T =>
type t = T
def ~=(e: T): Boolean
}
trait Base {
def as[T:ClassManifest]: Option[T] = {
if ( classManifest[T].erasure.isAssignableFrom( this.getClass ) ) Some( this.asInstanceOf[T] )
else None
}
def asMeta[T:ClassManifest]: Option[T with Meta[T]] = {
this match {
case meta: Meta[_] if classManifest[T] != ClassManifest.Nothing && classManifest[T] <:< meta.metaManifest => as[T].asInstanceOf[Option[T with Meta[T]]]
case _ => None
}
}
}
trait A extends Base
case class Ide(s: String) extends A
case class MIde(s: String) extends Meta[A] with A {
def ~=(e: A) = e match {
case e: Ide => true
case e: MIde => false
}
}
trait B extends Base
case class Foo(s: String) extends B
object Test {
val m = MIde("x")
val i = Ide("i")
val f = Foo("f")
def test[T:ClassManifest]() {
(m.asMeta[T], i.as[T]) match {
case (Some(x), Some(y)) if x ~= y => println("right")
case _ => println("wrong")
}
(m.asMeta[T], f.as[T]) match {
case (Some(x), Some(y)) if x ~= y => println("right")
case _ => println("wrong")
}
}
}
Finally, if neither solution suits you, you could try another one: instead of mixing Meta[T] with T, just wrap it. Meta[T] would then just be wrapper to T, and you could even add an implicit conversion from Meta[T] to its wrapped value, so that an instance of Meta[T] can effectively be used like an instance of T almost transparently.