Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Activity
  • 21:24
    Sciss opened #2032
  • 21:10
    Sciss opened #2031
  • 21:08
    joroKr21 commented #2027
  • 20:54
    superseeker13 commented #9637
  • 20:30
    dwijnand synchronize #1828
  • 18:39
    b-studios commented #1246
  • 18:37
    b-studios commented #1910
  • 18:37
    b-studios commented #1925
  • 18:36

    b-studios on main

    Settle on variable name fnf for… Use f-strings in Python to matc… Cleanup whitespace and 2 more (compare)

  • 18:36
    b-studios closed #2024
  • 18:20
    SethTisue synchronize #1416
  • 18:00
    SethTisue commented #1828
  • 18:00
    SethTisue commented #1910
  • 18:00
    SethTisue review_requested #1925
  • 17:59

    SethTisue on main

    Added to the tuple intro, relat… Update _overviews/scala-book/pr… Update _overviews/scala-book/pr… and 1 more (compare)

  • 17:59
    SethTisue closed #1932
  • 17:59
    SethTisue commented #1952
  • 17:59

    SethTisue on main

    Add consistency to parameter li… Add alternative formatting Re-word and 1 more (compare)

  • 17:59
    SethTisue closed #1952
  • 17:59

    SethTisue on main

    a weird sentence changed Merge pull request #1978 from x… (compare)

Luciano
@lJoublanc

Guys I have a question about implicit resolution. The resolution rules look by default in the companion of any types that are in the signature. So e.g. for (implicit fa: F[A]) it will check both the companion of F[_] and A and their related classes etc.
However, if I'm unable to extend these (e.g. shapeless.Typeable == F[_] and fs2.Chunk == A, both from external libraries), then I have to resort to explicitly importing the instances. Is there any way around this, to avoid the explicit import?
For a concrete example:

trait MyTypeclass[...] {
}

object MyTypeclass {
  implicit def typeableInstance[A]: Typeable[Chunk[A]] = ???
  implicit def myTcInstance(implicit: Typeable[Chunk[_]]): MyTypeclass = ???
}

When I want to use my typeclass in the above example, I always need to do

import MyTypeclass._
implicitly[MyTypeclass]

And if the library user doesn't know they need the first import statement. Really annoying. How can I work around this?

Fabio Labella
@SystemFw
right, you have an orphan instance, which generally requires an import
there might be a way to work around it, let me give it a shot
Fabio Labella
@SystemFw
object Lib1 {
  type Foo
}
object Lib2 {
  trait Name[A] { def name: String }
}

object Repro {
  trait UpperName[A] {
    def name: String
  }
  object UpperName {
    implicit def orphan[A]: Lib2.Name[Lib1.Foo] = new Lib2.Name[Lib1.Foo] {
      def name = "foo"
    }
    implicit def myTcInstance(
        implicit ev: Lib2.Name[Lib1.Foo]): UpperName[Lib1.Foo] =
      new UpperName[Lib1.Foo] { def name = ev.name.toUpperCase }
  }

  object Imports {
    import UpperName._
    val res = implicitly[UpperName[Lib1.Foo]].name // FOO

  }
  // Doesn't compile
  // object NoImports {
  //   val res = implicitly[UpperName[Lib1.Foo]].name
  // }
}

object Fix {
  trait UpperName[A] {
    def name: String
  }
  object UpperName {
    trait Carrier[TC[_], A] {
      def evidence: TC[A]
    }
    object Carrier {
      implicit def forNameFoo: Carrier[Lib2.Name, Lib1.Foo] = new Carrier[Lib2.Name, Lib1.Foo] {
        def evidence = orphan
      }
    }
    def orphan[A]: Lib2.Name[Lib1.Foo] = new Lib2.Name[Lib1.Foo] {
      def name = "foo"
    }

    implicit def myTcInstance(
        implicit ev: Carrier[Lib2.Name, Lib1.Foo]): UpperName[Lib1.Foo] =
      new UpperName[Lib1.Foo] { def name = ev.evidence.name.toUpperCase }
  }

  object NoImports {
    val res = implicitly[UpperName[Lib1.Foo]].name // FOO
  }
}
@lJoublanc there you go
you can simplify the solution a bit
i.e. with this solution you can move Carrier outside of the companion of UpperName, but if you don't need to do that then forNameFoo can be outside of the Carrier companion (which can be eliminated). orphan can be inlined as well, should you wish to do so
Luciano
@lJoublanc
Hi @SystemFw , as always, big thanks for taking the time to help out. So if I understand the trick here is to have a 'wrapper' (Carrier) that just holds the instance I need. And because it's in implicit scope of UpperName (MyTypeclass in my example), it will be picked up. Is that about right?
Fabio Labella
@SystemFw
not quite
Luciano
@lJoublanc
?
Fabio Labella
@SystemFw
the trick is that MyTypeclass now depends on Carrier, so the search includes the implicit scope of Carrier
Luciano
@lJoublanc

Right, so

And because it's in implicit scope of UpperName (MyTypeclass in my example), it will be picked up

is not correct

Fabio Labella
@SystemFw
nope
because your original code is also in the object
the reason why you can eliminate the companion of Carrier is because the object in which a TC is defined is also part of the scope of that TC
Luciano
@lJoublanc
Ok, got you. But the jist is that wrapping the typeclasses in a new type means that the implicit search changes from the companion of the original dependency to this new dependency.
Fabio Labella
@SystemFw
but if you move Carrier outside of UpperName's companion, then the instance needs to be in the companion of Carrier
@lJoublanc yes
Luciano
@lJoublanc
Ah, right, so I can remove object Carrier as long as I keep the instance in UpperName. I undestand now.
Fabio Labella
@SystemFw
it's the "complementary" trick to newtyping Chunk
I'm newtyping the typeclass
since I figure you most likely want to expose Chunk to the user as is
whereas Typeable is an implementation detail

Ah, right, so I can remove object Carrier as long as I keep the instance in UpperName. I undestand now.

:+1:

Luciano
@lJoublanc
Thanks for the help again. :)
Fabio Labella
@SystemFw
no problem :)
etienne
@crakjie
Is there some documentation about session management in functional programing lanaguage? ( database sessions )
Gavin Bisesi
@Daenyth
@crakjie doobie would be a great thing to look at design-wise
etienne
@crakjie
@Daenyth i'm reading that now http://tpolecat.github.io/presentations/doobie1.html#6 so I'm not far away from doobie source code ;)
Gavin Bisesi
@Daenyth
tldr; it defines a free monad that is conceptually wrapping JdbcConnection => A
Alwin
@alwins0n
hey guys, can I ask a newbie question?
Gavin Bisesi
@Daenyth
and then it has a Transactor[F: Effect] which wraps the thread pool and gives you transact: ConnectionIO ~> F
@alwins0n yup!
Alwin
@alwins0n
alright - i dont get y the following wont compile (imcopatible types)
Gavin Bisesi
@Daenyth
scalafiddle/scastie are quite helpful in fixing those btw
if you can put your example code there
Alwin
@alwins0n
  case class Bar[E](fx: E => E)

  trait BarBearing {
    def bars: List[Bar[this.type]]
  }

  case class Foo(bars: List[Bar[Foo]]) extends BarBearing
Gavin Bisesi
@Daenyth
this.type != Bar
this.type is the type of the instance of BarBearing
not the class
trepidacious
@trepidacious
Isn't Doobie moving to final tagless?
Gavin Bisesi
@Daenyth
@trepidacious yes, but Free and tagless are isomorphic
Alwin
@alwins0n
i thought this.type is the type of the actual instantiation. which would be Foo in the case of the case class Foo
Gavin Bisesi
@Daenyth
@alwins0n It's the type of a specific instance of foo
Alwin
@alwins0n
wait. this.type is supposed to be Foo
Gavin Bisesi
@Daenyth
val x: Foo = Foo(???)
val y: Foo = Foo(???
x.type =!= y.type
@alwins0n The term you want to look for, based on your code, is "F-bounded polymorphism"
and you may be better off not writing it this way
Alwin
@alwins0n
what do you mean?
Gavin Bisesi
@Daenyth
but something like
 trait BarBearing[A <: BarBearing] {
    def bars: List[Bar[A]]
  }
  case class Foo(bars: List[Bar[Foo]]) extends BarBearing[Foo]