Using typeclasses wtih multiple type parameters - scala

I'm trying to use symulacrum's #typeclass to avoid writing Ops/Syntax boilerplate. I have a trait parameterized with effect and a type:
#typeclass trait Close[F[_], T]{
def close(t: T): F[Unit]
}
With the intention to be used as follows:
trait Stream[F[_], Pipe]{
def open(): F[Pipe]
def drain(): F[Unit]
}
object App{
def runApp[F[_], Pipe: Close[F, ?]](implicit stream: Stream[F, Pipe]) = {
for{
pipe <- stream.open()
_ <- stream.drain(pipe)
_ <- pipe.close()
} yield ()
}
}
The reason I decided to put Close[F[_], T] away was that some Pipes in my application are inherently unclosable so it is kind of wierd to put
close method for all Pipes
This is the error I get:
Error:(32, 4) #typeclass may only be applied to types that take a single type parameter
#typeclass trait Close[F[_], T]
QUESTION: In case of a trait has multiple type parameters (like Close[F[_], T]) do I have to write all the Ops/Syntax boilerplate on my own and symulacrum's #typeclass cannot help here?

On your own.
https://github.com/mpilquist/simulacrum#known-limitations
Known Limitations
Only type classes that abstract over a proper type or a unary type constructor are currently supported.

Related

How to write for comprehension in cats with IO monad

I have the following code:
import cats.effect.IO
import cats.data.State
import cats.data.StateT
import cats.implicits._
import cats.effect.LiftIO
abstract class Example {
object implicits {
implicit def myEffectLiftIO: LiftIO[IOGameplay] =
new LiftIO[IOGameplay] {
override def liftIO[A](ioa: IO[A]): IOGameplay[A] = {
StateT.liftF(ioa)
}
}
}
type Gameplay[A] = State[GameState, A]
type IOGameplay[A] = StateT[IO, GameState, A]
type EitherDirection[A] = Either[Throwable, A]
type Map = Array[Array[FieldType]]
sealed trait FieldType
case class GameState(map: Map, block: Block)
case class Block(f1: Field, f2: Field)
case class Field()
import implicits._
val L = implicitly[LiftIO[IOGameplay]]
sealed trait GameResult
sealed trait Direction
trait IOMonad {
def println(msg: String): IO[Unit]
def readln(): IO[String]
}
def play(io: IOMonad): StateT[IO, GameState, GameResult] = {
val L = implicitly[LiftIO[IOGameplay]]
for {
// print map to the console
_ <- L.liftIO(io.println("Next move: "))
directionOpt <- L.liftIO(readDirection(io))
direction <- StateT.liftF[IO, GameState, Direction](IO.fromEither(directionOpt))
nextBlock <- IO(nextBlock(direction))
gameResult <- calculate(nextBlock)
} yield {
gameResult
}
}
def readDirection(io: IOMonad): IO[EitherDirection[Direction]]
def nextBlock(direction: Direction): Gameplay[Block]
def calculate(block: Block): Gameplay[GameResult]
}
This is not completely accurate, but I posted the whole block to explain the problem.
Here, I have many transformations on values to produce IO and to transform it to StateT. Is there a more clever way to do this? Maybe I should somehow separate io tasks from the main algorithm, i.e. from this for-comprehension? Or should I do it like this?
One issue is that your Gameplay type is not compatible with IOGameplay, since Gameplay uses the Eval monad. I assume you want this:
type Gameplay[F[_], A] = StateT[F, GameState, A]
type IOGameplay[A] = Gameplay[IO, A]
These methods need to return IOGameplay instances (or you could lift them in your program later):
def nextBlock(direction: Direction): IOGameplay[Block]
def calculate(block: Block): IOGameplay[GameResult]
Then the for-comprehension compiles with minor adjustments:
for {
// print map to the console
_ <- L.liftIO(io.println("Next move: "))
directionOpt <- L.liftIO(readDirection(io))
direction <- StateT.liftF[IO, GameState, Direction](IO.fromEither(directionOpt))
nextBlock <- nextBlock(direction)
gameResult <- calculate(nextBlock)
} yield {
gameResult
}
BTW, what is the intended purpose of the IO effect in this program? User input?
If your goal is to avoid lifting stuff from one monad to the other, then you can make your methods and interfaces polymorphic so that they can work with different monads and not just IO. Here's how to do that for your IOMonad trait:
trait IOMonad[F[_]] {
def println(msg: String): F[Unit]
def readln(): F[String]
}
The idea is to not commit to any specific monad, but to make things work for any monad that provides the features that you need for a specific use case. In the IOMonad example, we need the ability to run synchronous side effects, so we express that by passing a parameter of type Sync[F]:
import cats.effect.Sync
object IOMonad {
def apply[F[_]](implicit F: Sync[F]) = new IOMonad[F] {
def println(msg: String): F[Unit] = F.delay(println(msg))
def readln(): F[String] = F.delay(scala.io.StdIn.readLine())
}
}
The other operations in your program need different capabilities. For instance readDirection needs to do console IO and raise errors of type Throwable. The ability to raise errors is expressed by the MonadError trait, so you get this signature:
def readDirection[F[_]](
io: IOMonad[F])(implicit monErr: MonadError[F, Throwable]
): F[Direction]
It's important to note that we're not passing a Sync[F] here, because we don't need it; the IOMonad[F] object is enough. This is important because it allows you to implement the IOMonad interface in some other way that doesn't necessarily involve side effects, notably for testing.
Another example are nextBlock and calculate. These need manipulate a state of type GameState, and the ability to manipulate state is expressed by the MonadState type:
def nextBlock[F[_]](
direction: Direction)(implicit F: MonadState[F, GameState]
): F[Block]
def calculate[F[_]](
block: Block)(implicit F: MonadState[F, GameState]
): F[GameResult]
MonadState is unfortunately not contained in cats or cats-effect, you need the cats-mtl library for that.
When you put all this together, you end up with a program like this:
import cats.MonadError
import cats.mtl.MonadState
import cats.implicits._
abstract class Example {
type Map = Array[Array[FieldType]]
sealed trait FieldType
case class GameState(map: Map, block: Block)
case class Block(f1: Field, f2: Field)
case class Field()
sealed trait GameResult
sealed trait Direction
trait IOMonad[F[_]] {
def println(msg: String): F[Unit]
def readln(): F[String]
}
def play[F[_]](
io: IOMonad[F])(
implicit merr: MonadError[F, Throwable],
mst: MonadState[F, GameState]
): F[GameResult] = {
for {
// print map to the console
_ <- io.println("Next move: ")
direction <- readDirection(io)
nextBlock <- nextBlock[F](direction)
gameResult <- calculate[F](nextBlock)
} yield gameResult
}
def readDirection[F[_]](
io: IOMonad[F])(
implicit merr: MonadError[F, Throwable]
): F[Direction]
def nextBlock[F[_]](
direction: Direction)(
implicit merr: MonadState[F, GameState]
): F[Block]
def calculate[F[_]](
block: Block)(
implicit mst: MonadState[F, GameState]
): F[GameResult]
}
Note that every single concrete Monad is gone – there is no IO, no State, no Either in the above program, and together with these, any necessity to convert or lift between different monads also went away.
Note however that this style of programming (known as MTL-Style) has its drawbacks.
type inference often doesn't work. In this example you need to pass the F parameter explicitly to nextBlock and calculate, because Scala can't infer it
as mentioned before, cats doesn't include all the necessary type classes like MonadState, so you need additional libraries like cats-mtl
it's somewhat hard to understand for newcomers
This is why parts of the Scala community (notably John de Goes and his ZIO effort) are no longer encouraging MTL-style. Others keep pushing it, because it allows code to be reused with different effect types.

Shapeless not working in generic context

I am still trying to get my head around Shapeless (and, to a lesser extent, Scala!) and I have been writing some simple code to generate random instance data for case classes - predominantly based on the guides here: http://enear.github.io/2016/09/27/bits-of-shapeless-2/ (the example covers a JSON Writer implementation)
I have created a Generator[A] trait and created implicit implementations for simple types, and as per the example in the above link, I have also created implicit implementations to handle HList, HNil, Coproduct and CNil:
implicit def hnilGenerator = new Generator[HNil] {
override def generate(a: HNil) = HNil
}
implicit def hconsGenerator[H, T <: HList](implicit headGen: Generator[H], tailGen: Generator[T]) =
new Generator[H :: T] {
override def generate(a: H :: T) = headGen.generate(a.head) :: tailGen.generate(a.tail)
}
implicit def cnilGenerator: Generator[CNil] =
new Generator[CNil] {
override def generate(a: CNil): CNil = throw new RuntimeException("Invalid candidate configuration")
}
implicit def cconsGenerator[H, T <: Coproduct] =
new Generator[H :+: T] {
override def generate(a: H :+: T) = throw new RuntimeException("Invalid candidate configuration")
}
I can now use this code to generate a random instance based on a case class or a sealed trait:
it("should work with a case class to hlist") {
case class Test(x: IntGene, y: DoubleGene, z: BooleanGene)
val c = Generic[Test].to(Test(IntGene(), DoubleGene(), BooleanGene()))
generate(c)
}
it("what happens with sealed traits") {
sealed trait Shape
case class Square(width: Int, height: Int) extends Shape
case class Circle(radius: Int) extends Shape
val c = Generic[Shape].to(Circle(1))
generate(c)
}
Both of the above work no problem, however, if I try to make this a generic (as in parameter types) I get compilation errors not being able to find the necessary implicts:
it("should handle generics") {
case class GenericTest[A: Generic](x: A) {
def convert() = {
val c = Generic[A].to(x)
generate(c)
}
}
}
So from my understanding, because I have used the Generic context bound A, the compiler knows that is going to be available, so c must be some possible return from the call to(x) - Am I missing something in the implementation to handle that return type from the Generic shapeless call? Or have I wildly misunderstood something?
I am hoping this is possible and I have just missed something - is it that the compiler doesn't know what will be passed in (Im assuming not), or is there another possible type that needs to be handled implicitly from that to(x) call?
EDIT
Compile error added below - I'm really just trying to understand: Is it that there is some return case from the to(x) shapeless call that I have not catered for, or is it because the compiler doesn't have any idea what will be passed in and there are some types not catered for (e.g. I haven't added a Date generator implicit - and a case class could potentially have any type included? I was hoping that was not the case, and as the compiler knows nothing is actually being passed to the class/method it knows there are no issues?)
GeneratorSpec.scala:44: could not find implicit value for parameter gen: io.github.robhinds.genotype.Generator[GenericTest.this.evidence$1.Repr]
generate(c)
And my generate method is just a simple helper method that gets given the implicit Generator :
def generate[A](a: A)(implicit gen: Generator[A]) = gen.generate(a)
Your problem comes from the fact that Generic only converts a case class to a HList and a sealed trait to a Coproduct (not recursively).
So if you have a generic Generic, you have no information on what HList or Coproduct you are given, so, you cannot use your product and coproduct rules to find the wanted implicit. In some explicit case, you might have the same problem, so I will give you this as an example:
Let's say you have a case class architecture
case class Bottom(value: String)
case class Top(bot: Bottom, count: Int)
The implicit Generic[Top] will have type MyHList = Bottom :: Int :: HNil as output type, so you'll be asking for an implicit Generator[MyHList]. But since you don't have an implicit Generator[Bottom] in scope, you won't be able to use hconsgenerator.
In the generic case, it's even worse. The compiler can only infer HList for the output type of Generic[A] (and that's assuming you forget about Coproduct), so you need an implicit Generator[HList], which you cannot provide.
The solution is to give an implicit for constructs that have a generic that can itself be generated:
implicit def generic2generate[T, L <: HList](implicit generic: Generic.Aux[T, L], lGen: Generator[L]): Generator[T] = new Generator[T] {
def generate(c: T) = generic.from(lGen.generate(generic.to(c)))
}
EDIT
You can now follow the implicit resolution for our Top type:
We can have a Generator[Top] using last rule, if we have a Generic.Aux[Top, L] for some L, and a Generator[L].
The only Generic.Aux[Top, _] that exists implicitly is a Generic.Aux[Top, Bottom :: Int :: HNil], so we are reduced to finding a Generator[Top, Bottom :: Int :: HNil]
using the hcons rule three times, we are reduced to finding a Generator[Bottom], a Generator[Int] and a Generator[HNil].
Generator[Int] is given (I assume) and Generator[HNil] is the first rule, so we are reduced to finding a Generator[Bottom]
the only rule that can provide one, is once again the 3rd rule, so we must find a Generator[String :: HNil], since the only Generic available is a Generic.Aux[Bottom, String :: HNil].
using the hcons rule, we are down to finding a Generator[String], which can easily be provided.
This example shows different points:
first that it may take a long time when compiling to solve all these implicits (I only gave the main points of the proof, but the compiler has to try all possible branches)
second, that this resolution can only be done for a specific Generic, it cannot be inferred generically (although this might seem counter-intuitive); even if the human mind is able to tell that it will work for every Generic, the compiler cannot process it as such.
I think you are missing the Generator type bound.
it("should handle generics") {
case class GenericTest[A: Generic : Generator](x: A) {
def convert() = {
val c = Generic[A].to(x)
generate(c)
}
}
}

Implicit not found for partially applied type

While this problem was caught in code using shapeless and kind-projector, this behavior could be reproduced without them.
Suppose I have simple typeclass for reifying typeclass instances with incomplete implementation (mirror of LiftAll).
sealed trait LiftAll1[F[_], In] {
type Out
def instances: Out
}
object LiftAll1 {
type Aux[F[_], In0, Out0] = LiftAll1[F, In0] {type Out = Out0}
implicit def unit[F[_]]: Aux[F, Unit, Unit] = new LiftAll1[F, Unit] {
type Out = Unit
def instances = Unit
}
}
And some very simple type class to test it
sealed class FirstIs[M, T]
object FirstIs {
implicit def firstIs[M, D]: FirstIs[M, (M, D)] = new FirstIs
}
Things are ok if I'll try to apply FirstIs partially via alias, and get instance via LiftAll1
type FirstIsInt[D] = FirstIs[Int, D]
implicitly[LiftAll1[FirstIsInt, Unit]]
But inlined partial type application leads to compilation error
implicitly[LiftAll1[({type lambda[x] = FirstIs[Int, x]})#lambda, Unit]]
//Error: could not find implicit value for parameter e: LiftAll1[[x]FirstIs[Int,x],Unit]
How partially applied typeclasses could be found in such situations?
As #Reactormonk suggested, the compiler was brought to its senses with following line in the build.sbt
scalacOptions += "-Ypartial-unification"
After that original piece of code, which is close to
import shapeless._, ops.hlist._
LiftAll[FirstIs[Int, ?], HNil]
was succesfully compiled
AFAIK problem was in scala compiler incapability to understand FirstIs[Int,_] as F[_]in supplied implicit def without direct type alias . Fortunately this was fixed in latest scala implementations.

How to get an implicit instance like TypeTag does in a method?

I am struggling with a problem and I can't realise how to solve it. I hope more experienced Scala programmers can shed me a light!
I have the following macro:
object Model {
trait Model[T <: Product] {
def showAttrs(): Unit
}
def getModel[T <: Product]: Model[T] = macro getModelImpl
}
The purpose of the macro is to return a Model instance that shows the T's attributes (if T is a case class)!
I want to be able to do the following:
def f[T <: Product](implicit m: Model[T]): Unit = {
m.showAttrs()
}
case class Number(n: Int)
f[Number]()
The principle is the same as scala reflection when we do the following:
case class Number(n: Int)
def getInfo[T](implicit tag: TypeTag[T]): Unit = println(tag)
See?! We get an instance of Type :) (GREAT!).
How to do such thing? Does the scala reflection package provide some concrete implicit behind the scenes? If so, how can I accomplish the same result?
What should your MyTypeTag[T] accomplish?
If your trait is invariant on T and has not any type-dependent logic at all, simplest solution could be define method
implicit def arbMyTypeTag[T] = new MyTypeTag { ... }
More complex variant depends on other resolved implicits
implicit def optionMonoid[T: Semigroup] = new Monoid[Option[T]] { ... }
Even more complex variant depends on same type
implicit def tupleMonoid[A,B](implicit ma: Monoid[A], mb: Monoid[B]) = new Monoid[(A,B)]{...}
Compiler is able to resolve such recursive implicits.
The most hardcore approach is to use whole compile-time information on type and expression via implicit macro which is the closest to things like TypeTag resolution, which could lead to very complex bugs

Defining a method whose return type is the singleton type of an argument of that method

Still struggling with this.types (singleton types). Assume this scenario:
trait Sys[A <: Access] {
def in[T](v: String): AccessPrepare[A]
}
trait AccessPrepare[A <: Access] {
val a: A
def apply[T](fun: a.type => T): T
}
object Ref {
def single[A <: Access, V](v: V)(implicit a: A): Ref[A, V] = ???
}
trait Ref[A, V]
trait Access {
def set(r: Ref[this.type, Int]): Unit
}
The following fails:
def test(sys: Sys[Access]): Unit =
sys.in("v1") { implicit a =>
val r = Ref.single(44)
a.set(r)
}
because apparently r is of type Ref[Access, Int] and not Ref[a.type, Int]. My guess is the problem is that I would need a line like
def single[A <: Access, V](v: V)(implicit a: A): Ref[a.type, V] = ...
which isn't compiling as due to "illegal dependent method type"...
Any ideas how I can fix this. The demand is that I do not explicitly annotate calls with types. That is, I do not want to write Ref.single[a.type, Int](44)(a) for comprehensible reasons.
EDIT
As a clarification, with reference to answer "FYI, and to close the question" in thread Constraining an operation by matching a type parameter to an argument's path-dependent type -- what I would like to have in addition is the possibility to create objects (Refs) not by using a factory method in the Access but somewhere outside (e.g. with a new statement). Because the system cannot be limited by the definition of Access, I must be able to extend it with further objects.
You have several possibilities. With Scala 2.8/2.8.1, you can use the private option -Ydependent-method-types and then your solution with
def single[ A <: Access, V ]( v: V )( implicit a: A ) : Ref[ a.type, V ] = // ...
compiles fine.
If you want to avoid dependent method types because it's a private option, you can still make your first proposal compile by explicitly typing the call to Ref.single:
val r = Ref.single[a.type, Int](44)
You need to specify the type, though, as singleton types are never inferred. You problem is not the same as, but related to, the problem that singleton types are not inferred: see How to correctly type-annotate this HList?