Cannot find Bind instances for Free Monads over Coyoneda when composing functions via Kleisli arrows

105 views
Skip to first unread message

Vadim Belobrovka

unread,
Sep 10, 2015, 8:30:51 AM9/10/15
to scalaz

Thank you in advance for your help


I have 2 functions that I am trying to compose via Kleisli arrows. The functions accept String and produce FreeC. The kleisli arrows are created without an issue but the compiler is complaining that it cannot find. I will cut out some of the code for simplicity:


import scalaz._
import Scalaz._
import Free.FreeC
import Free._
import Kleisli._

type FreeString[A] = FreeC[F,String]

def lift[F[_], G[_], A](fa: F[A])(implicit I: Inject[F, G]): FreeC[G, A] =
Free.liftFC(I.inj(fa))

sealed trait Sensor[A]
case class Filter(log: String) extends Sensor[String]
case class Secure(log: String) extends Sensor[String]


def filter(log: String) = lift(Filter(log))
def secure(log: String) = lift(Secure(log))

val fk = kleisli[FreeString, String, String](filter _)
val sk = kleisli[FreeString, String, String](secure _)
val fAndS = sk >=> fk


For some reason what i get is this compilation error:


could not find implicit value for parameter b: scalaz.Bind[FreeString]
[error]   val fAndS = sk >=> fk


feels like the implicit should be resolved since FreeC in a monad instance that implements a Bind trait and i am importing all of the Free implicit instances via import Free._


what am I missing here?


Thank you in advance!

Colt Frederickson

unread,
Sep 10, 2015, 10:25:29 AM9/10/15
to scalaz
Your code doesn't compile. FreeString doesn't have an F in it and doesn't use A. I assume by what you have here that FreeString should actually be FreeSensor. If that's true you can replace FreeString with 

type FreeSensor[A] = Free.FreeC[Sensor,A]

Then you'll need to explicitly create a monad instance for that type which will allow your fk and sk to compile.

//Note you'll need kind projector to compile this, otherwise use a type lambda.
implicit val MonadFreeSensor: Monad[FreeSensor] = Free.freeMonad[Coyoneda[Sensor, ?]]

Colt
--
You received this message because you are subscribed to the Google Groups "scalaz" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scalaz+un...@googlegroups.com.
To post to this group, send email to sca...@googlegroups.com.
Visit this group at http://groups.google.com/group/scalaz.
For more options, visit https://groups.google.com/d/optout.

Robert Norris

unread,
Sep 10, 2015, 11:31:32 AM9/10/15
to sca...@googlegroups.com

Then you'll need to explicitly create a monad instance for that type which will allow your fk and sk to compile.

//Note you'll need kind projector to compile this, otherwise use a type lambda.
implicit val MonadFreeSensor: Monad[FreeSensor] = Free.freeMonad[Coyoneda[Sensor, ?]]

This becomes in inferable with some unapply machinery, which I have thus far failed to make a PR for. If you have a bunch of instances then it may be easier to just bring these two definitions into scope.


rob


Vadim Belobrovka

unread,
Sep 10, 2015, 3:26:36 PM9/10/15
to scalaz
thank you so much for the reply

I am very sorry - in the effort to be brief i have trimmed out too much context to the code:

The type declareration is correct but comes with more context. I just tested the code and it should compile:

import scalaz._
import Scalaz._
import Free.FreeC
import Free._
import Kleisli._

trait AppCompose {


  def lift[F[_], G[_], A](fa: F[A])(implicit I: Inject[F, G]): FreeC[G, A] =
    Free.liftFC(I.inj(fa))

}

object BigBrother {

  sealed trait Sensor[A]
  case class Log(log: String) extends Sensor[Unit]

  case class Filter(log: String) extends Sensor[String]
  case class Secure(log: String) extends Sensor[String]

}

import BigBrother.Sensor

class BigBrother[F[_]](implicit I: Inject[Sensor,F]) extends AppCompose {
  import BigBrother._

  
type FreeString[A] = FreeC[F,String]


  def log(log: String) = lift(Log(log))

  def filter(log: String) = lift(Filter(log))
  def secure(log: String) = lift(Secure(log))


  def filterAndSecure(phrase: String) = for {
    f <- filter(phrase)
    s <- secure(f)
  } yield s

  // kleisli composition attempt - alternative to filterAndSecure

  val fk = kleisli[FreeString, String, String](filter _)
  val sk = kleisli[FreeString, String, String](secure _)

  val fAndS = fk >=> sk // this is where we have a compilation issue

}

Did not mean to waste time :)

Vadim Belobrovka

unread,
Sep 10, 2015, 9:26:38 PM9/10/15
to scalaz
thank you very much for your help! the key was in both: correct type declaration and providing the monad implicit. Here is the code:

class BigBrother[F[_]](implicit I: Inject[Sensor,F]) extends AppCompose {
 
import BigBrother.
_


 
def log(log: String) = lift(Log(log))

 
def filter(log: String) = lift(Filter(log))
 
def secure(log: String) = lift(Secure(log))


 
def filterAndSecure(phrase: String) = for {
    f
<- filter(phrase)
    s
<- secure(f)
 
} yield
s


  type
CoyoF[A] = Coyoneda[F, A]
  type
FreeCoF[A] = Free[CoyoF,A]


 
implicit val MonadFreeSensor = Free.freeMonad[FreeCoF]


 
// kleisli composition attempt
  val fk
= kleisli[FreeCoF, String, String](filter _)
  val sk
= kleisli[FreeCoF, String, String](secure _)

  val fAndS
= fk >=> sk


}


If you dont mind I have a followup: Free.freeMonad is actually implicit and is imported in scope so how can more elegantly point to FreeCoF type as a monad instance without explicitly rewrapping? I hope I am explaining myself clearly enough ...

Colt Frederickson

unread,
Sep 11, 2015, 1:20:54 AM9/11/15
to scalaz
I believe this is what Rob was getting at by linking you to his work he's done in doobie. If you replicate these instances it can be inferred. 

Vadim Belobrovka

unread,
Sep 11, 2015, 8:30:49 AM9/11/15
to scalaz
Thanks guys!
Reply all
Reply to author
Forward
0 new messages