Scala Natural Transformation from DSL to Function - scala

I'm trying to perform a Natural Transformation between kinds of * -> * -> *
so I want to take F[A, B] => G[A, B]
Specifically I'm trying to define a DSL that I can then convert into actual function definitions, so MyDSL[A, B] => Function[A, B]
Here is the Natural Transformation definition:
trait ~~>[F[_, _], G[_, _]] {
def apply[A, B](fab: F[A, B]): G[A, B]
}
object ~~> {
def apply[F[_, _], G[_, _]](implicit f2g: F ~~> G): F ~~> G = f2g
}
The DSL looks like so:
sealed trait MyDSL[A, B]
object MyDSL {
case object Add1 extends MyDSL[Int, Int]
case object Show extends MyDSL[Int, String]
implicit def dsltoF: MyDSL ~~> Function = new ~~>[MyDSL, Function] {
override def apply[A, B](fab: MyDSL[A, B]): Function[A, B] = fab match {
case Add1 => i => i + 1
case Show => i => i.toString
}
}
}
Using the Natural Transformation directly works fine:
dsltoF(Add1)
output: res0: Function[Int,Int] = MyDSL$$anon$2$$Lambda$1816/700824958#6f3aa425
It even works in the case where the function returned is a method taking 2 type parameters.
When I try to define a DSL object that converts using a generic method of one type parameter it has issues.
case class Id[A]() extends MyDSL[A, A]
implicit def dsltoF: MyDSL ~~> Function = new ~~>[MyDSL, Function] {
override def apply[A, B](fab: MyDSL[A, B]): Function[A, B] = fab match {
case Id() => identity[A] _
case Add1 => i => i + 1
case Show => i => i.toString
}
}
I get a found A required B compilation error.
Scala doesn't recognize that B is A in this case.
I get why, as the type parameters A & B aren't necessarily correlated properly to the definition of the function I am returning, therefore even writing:
case Add1 => i => i + 1
there is red lines in IntelliJ as it doesn't realize that even though Add "is a" MyDSL[Int, Int]. Though Scala is ok with this.
The type parameters are open to all possibilities on the method signature of apply on the Natural Transformation, but in this case it needs some sort of restriction. My guess is since there is no value within the DSL case class to restrict the type parameter, it comes down to the pattern match, which is already past where Scala interprets the signature of the method, and therefore it expects a different type B and it barks.
I can of course get around this via .asInstanceOf nastiness, but I mean come on.
Any thoughts of a different strategy to get this to work would be appreciated.

That's a known restriction in the type inference system in the current versions of the language, which should be lifted in future versions.
In this case, you can use type variables in the pattern match to work around this restriction:
import scala.language.higherKinds
trait ~~>[F[_, _], G[_, _]] {
def apply[A, B](fab: F[A, B]): G[A, B]
}
object ~~> {
def apply[F[_, _], G[_, _]](implicit f2g: F ~~> G): F ~~> G = f2g
}
sealed trait MyDSL[A, B]
object MyDSL {
case class Id[A]() extends MyDSL[A, A]
case class Const[A, B](constantResult: B) extends MyDSL[A, B]
case object Add1 extends MyDSL[Int, Int]
case object Show extends MyDSL[Int, String]
implicit def dsltoF: MyDSL ~~> Function = new (MyDSL ~~> Function) {
override def apply[A, B](fab: MyDSL[A, B]): Function[A, B] = fab match {
case _: Id[x] => identity[x] _
case c: Const[a, b] => (_ => c.constantResult)
case Add1 => i => i + 1
case Show => i => i.toString
}
}
}
Essentially: if there is no "place" where the compiler could deposit more specific type information, just give it a type-variable in the pattern so it can attach the inferred type information to it.

Related

Scala compiler infers overly specific type with complex type parameter

I'm writing an FRM, with the fields abstracted over F[_].
trait Query[A]
case class Field[A](name: String)
case class DBTable[T[_[_]]](fields: T[Field]) extends Query[T[Field]]
// example table
case class PersonalInfo[F[_]](name: F[String], age: F[Int])
I want to perform query rewrites using recursion schemes, so I need to define a pattern functor,
trait QueryF[A, B]
case class DBTableF[T[_[_]], B](fields: T[Field]) extends QueryF[T[Field], B]
and then a coalgebra to lift the Query into it:
type Coalgebra[F[_], A] = A => F[A]
def coalg[A]: Coalgebra[QueryF[A, ?], Query[A]] = {
case DBTable(fields) => DBTableF(fields)
}
This works, but defining an algebra to convert in the opposite direction does not:
type Algebra[F[_], A] = F[A] => A
def alg[A]: Algebra[QueryF[A, ?], Query[A]] = {
case DBTableF(value) => DBTable[A](value)
}
the alg function throws a compiler error, saying constructor of type controllers.thing.DBTableF[T,B] cannot be uniquely instantiated to expected type controllers.thing.QueryF[?,controllers.thing.Query[?]
How about this here:
import scala.language.higherKinds
trait Query[A]
case class Field[A](name: String)
case class DBTable[T[_[_]]](fields: T[Field]) extends Query[T[Field]]
trait QueryF[A, B]
case class DBTableF[T[_[_]], B](fields: T[Field]) extends QueryF[T[Field], B]
type Coalgebra[F[_], A] = A => F[A]
def coalg[A]: Coalgebra[({ type L[X] = QueryF[A, X]})#L, Query[A]] = {
case DBTable(fields) => DBTableF(fields)
}
type Algebra[F[_], A] = F[A] => A
def alg[A]: Algebra[({ type L[X] = QueryF[A, X]})#L, Query[A]] = {
case dbtf: DBTableF[t, b] => DBTable(dbtf.fields)
}
or alternatively, with the last case replaced by:
case dbtf: DBTableF[t, b] => DBTable[t](dbtf.fields)
if this is a bit clearer.
Both variants compile with -Ypartial-unification on 2.12.6.

how to define upper bounds for scala method

how do you define a Scala method such that it would take in the subclass of any type A without throwing a compilation error?
trait A
case class B extends A
case class C extends A
case class W[T](abc: Option[T]= None)
def methodOne(a: A): W[A] = {
a match {
case b:B => methodTwo() // throws compilation error
case c:C => methodThree() // throws compilation error
}
}
def methodTwo(): W[B] = y
def methodThree(): W[C] = z
Have tried something like
def methodOne[T <: A](a: A): W[T]
but it doesn't allow to compile still
If you want forall T <: A to imply W[T] <: W[A], you need to make W covariant:
case class W[+T](abc: Option[T] = None)
object X {
def methodOne(a: A): W[A] = {
a match {
case b: B => methodTwo()
case c: C => methodThree()
}
}
def methodTwo(): W[B] = ???
def methodThree(): W[C] = ???
}
For basic coverage of variance, see this post.
You need to make W covariant. You can do this easily by defining it as W[+T]:
case class W[+T](abc: Option[T] = None)
This way if B is a subtype of A, W[B] is also a subtype of W[A].
Option for example is defined as Option[+T], therefore Option[B] is a subtype of Option[A].
You can checkout the official scala docs for more details

(co | in)variance of Higher Kinded type parameter

the code in question
trait Functor[F[_]] {
def map[A, B](f: A => B): F[A] => F[B]
}
sealed abstract class Free[F[_], A]
case class Return[F[_], A](x: A) extends Free[F, A]
case class Suspend[F[_], A](x: F[Free[F, A]]) extends Free[F, A]
case class Bind[F[_], A, B](x: () => Free[F, A], f: A => Free[F, B]) extends Free[F, B]
// this is the problem child
def liftF[F[_], A](x: => F[A])(implicit F: Functor[F]) =
Suspend[F, A](F.map { Return[F, A] }(x))
Now for some reason in the eclipse scala ide I'm getting a error with liftF
this error
- type mismatch; found : F[core01.Free.Return[F,A]] required: F[core01.Free[F,A]] Note: core01.Free.Return[F,A] <: core01.Free[F,A], but type
F is invariant in type _. You may wish to define _ as +_ instead. (SLS 4.5)
Now in the scalaz source there's no variance annotation, so what's the deal here? why the need for the variance annotation? is there are really need or is there a way around it?
I think you just have the functor arguments backwards on F.map. Give this a try:
def liftF[F[_], A](x: => F[A])(implicit F: Functor[F]) =
Suspend[F, A](F.map(x) { Return[F, A] } )
println(liftF(List(1, 2)))
"Suspend(List(Return(1), Return(2)))"
Note that either way you apply the elements to functor map you'll get the same result (you're version and the scalaz version):
def mapReverse[F[_], A, B](implicit F: Functor[F]) = {
(f:A => B) => (fa:F[A]) => F.map(fa)(f)
}
val reverse = mapReverse(F)({
Return[F, A]
})(x)
val normal = F.map(x)({
Return[F, A]
})
In this case reverse and normal are both F[Return[F, A]]. The way you apply the parameters is only helpful in the context of Suspend:
Suspend[F, A](F.map(x)({ Return[F, A] })) // works great
Suspend[F, A](normal) // fails to compile
Suspend[F, A](reverse) // fails to compile
I'm sure if you dig through the scala language spec long enough you can find out why the type inference works this way. If I had to guess, when fa is applied to F.map you get a function that's of type (A => B) => F[B]. So the compiler probably looks and sees that Suspend takes a Free so it makes this (A => Free[F, A]) => F[Free[F, A]] which will gladly take Return[F, A].apply as an argument. When you apply the arguments the other way you're strongly typed to Return instead of inferring a function Free.

Type projection example from "Scala in Action" (chapter 8)

could anyone help me with below code bits from the book?
trait Mapper[F[_]] {
def fmap[A, B](xs: F[A], f: A => B): F[B]
}
def VectorMapper = new Mapper[Vector] {
def fmap[A, B](xs: Vector[A], f: A => B): Vector[B] = xs map f
}
That was simple: trait definition using higher-kinded type F[_] for usage with any "container-like" types, then a concrete mapper for Vector.
Then goes a tricky part. Mapper for Either.
I understand {type E[A] = Either[X, A]} just as a block of code, and ({type E[A] = Either[X, A]})#E as a projection that takes that type alias E out of the anonymous block of code and by that author "hides" the presence of X for the Mapper trait because trait operates on single type parameter "container types" only - and we are interested in A, i.e. Right.
def EitherMapper[X] = new Mapper[({type E[A] = Either[X, A]})#E ] {
def fmap[A, B](r: Either[X, A], f: A => B): Either[X, B] = r match {
case Left(a) => Left(a)
case Right(a) => Right(f(a))
}
}
Question:
Why do we need X in the def EitherMapper[X] = part?
Thanks for details.
Either is dependent on two types, for instance Either[Int, String]
EitherMapper is a type constructor that is dependent just on one type, so when you have a EitherMapper[Int], you are dealing with a Either[Int, A], and A is resolved into the Mapper part, this way you can have any A=>B function, because the first type of Either is already present for the Mapper and you return a Either[X, B].
Indeed the type E[A] is equivalent to Either[X, A], you have just one degree of freedom regarding to types!
val right: Either[Boolean, String] = Right("test")
val left: Either[Boolean, String] = Left(false)
println(EitherMapper.fmap(right, (s: String) => s.length))
> Right(4)
println(EitherMapper.fmap(left, (s: String) => s.length))
> Left(false)
In this case the type is EitherMapper[Boolean] and the type of fmap is fmap[String, Integer], it accepts Either[Boolean, String] and return Either[Boolean, Integer].
As you can see the type of fmap doesn't say anything on the X part of the Either[X, A] type so in the end you could use the (s: String) => s.length) function for others EitherMapper[X] types, in simple words the "left" part of the either type can be anything you want, and it's the "X" part of the type construction.
Hope it's clearer now!

Scala: Type inference and subtypes/higher-kinded-types

I've been playing around with Scalaz to get a little bit of the haskell feeling into scala. To
understand how things work in scala I started implementing various algebraic structures myself and came across a behavior that has been mentioned by the Scalaz folks.
Here is my example code which implements a functor:
trait Functor[M[_]] {
def fmap[A, B](a: M[A], b: A => B): M[B]
}
sealed abstract class Foo[+A]
case class Bar[A]() extends Foo[A]
case class Baz[A]() extends Foo[A]
object Functor {
implicit val optionFunctor: Functor[Option] = new Functor[Option]{
def fmap[A, B](a: Option[A], b: A => B): Option[B] = a match {
case Some(x) => Some(b(x))
case None => None
}
}
implicit val fooFunctor: Functor[Foo] = new Functor[Foo] {
def fmap[A, B](a: Foo[A], b: A => B): Foo[B] = a match {
case Bar() => Bar()
case Baz() => Baz()
}
}
}
object Main {
import Functor._
def some[A](a: A): Option[A] = Some(a)
def none[A]: Option[A] = None
def fmap[M[_], A, B](a: M[A])(b: A => B)(implicit f: Functor[M]): M[B] =
f.fmap(a, b)
def main(args: Array[String]): Unit = {
println(fmap (some(1))(_ + 1))
println(fmap (none)((_: Int) + 1))
println(fmap (Bar(): Foo[Int])((_: Int) + 1))
}
}
I wrote a functor instance for Option and a bogus sumtype Foo. The problem is that scala cannot infer the implicit parameter without an explicit type annotation or a wrapper method
def some[A](a: A): Option[A] = Some(a)
println(fmap (Bar(): Foo[Int])((_: Int) + 1))
Scala infers types like Functor[Bar] and Functor[Some] without those workarounds.
Why is that? Could anyone please point me to the section in the language spec that defines this behavior?
Regards,
raichoo
You're asking the compiler to perform two tasks: local type inference (§6.26.4) of the type arguments to fmap, and an implicit search for implicit parameter (§7.2) f. References are to the Scala Reference.
Things go in roughly this order:
fmap[M = ?, A = ?, B = ?](Some(1))(x => x)
// type the arguments of the first parameter section. This is done
// without an expected type, as `M` and `A` are undetermined.
fmap[M = ?, A = ?, B = ?](Some(1): Some[Int])(x => x)(?)
// local type inference determines `M` and `A`
fmap[Some, Int, B = ?](Some(1): Some[Int])(x => x)(?)
// move to the second parameter section, type the argument with the expected type
// `Function1[Int, ?]`. The argument has the type `Function1[Int, Int]`
fmap[Some, Int, ?](Some(1): Some[Int])((x: Int) => x)
// local type inference determines that B = Int
fmap[Some, Int, Int](Some(1): Some[Int])((x: Int) => x)
// search local identifiers, and failing that the implicit scope of type `Functor[Some]]`, for an implicit
// value that conforms to `Functor[Some]`
fmap[Some, Int, Int](Some(1): Some[Int])((x: Int) => x)(implicitly[Functor[Some]])
The implicit search for Functor[Some] fails; Functor[Option] doesn't conform.