How can I write a recursive polymorphic function with Shapeless - scala

I can write a simple recursive polymorphic function:
object simpleRec extends Poly1 {
implicit def caseInt = at[Int](identity)
implicit def caseList[A, B](implicit ev: simpleRec.Case.Aux[A, B]) =
at[List[A]](_.headOption.map(simpleRec))
}
This seems to largely do what I want; however, I seem to be getting a nonsensical result type:
scala> simpleRec(List.empty[List[Int]])
res3: Option[B] = None
scala> simpleRec(List(List(1)))
res4: Option[B] = Some(Some(1))
How can I make this give me values of Option[Option[Int]] rather than Option[B]? I expect I'm making some silly mistake here, but can't work out what it is.

This probably was a bug, the following code works as expected:
object simpleRec extends Poly1 {
implicit def caseInt = at[Int](identity)
implicit def caseList[A](implicit ev: simpleRec.Case[A]) =
at[List[A]](_.headOption.map(simpleRec))
}
Using shapeless_2.11-2.0.0

Related

SYB `cast` function in Scala

I am reading the Scrap Your Boilerplate paper and trying to follow along by implementing the ideas in scala as best I can. However, I'm stuck on the very first function, the cast, which is used to take a value and attempt to cast it to another type in an Option, obviously a Some if the cast is successful, and None otherwise. I have a version of it working with the following code:
trait Cast[A, B]:
def apply(a: A): Option[B]
object Cast:
given cSome[A, B](using t: A =:= B): Cast[A, B] with
def apply(a: A) = Some(t(a))
given cNone[A, B](using t: NotGiven[A =:= B]): Cast[A, B] with
def apply(a: A) = None
This works when types are statically known. Trying the examples from the paper:
val maybeChar = summon[Cast[Char, Char]]('a') // Some(a)
val maybeBool = summon[Cast[Char, Boolean]]('a') // None
val maybeBool2 = summon[Cast[Boolean, Boolean]](true) // Some(true)
However, when I try to clean up the ergonomics a bit so that we can rely on type inference as in the examples in the paper with a generic helper defined as such:
def cast[A, B](a: A): Option[B] = summon[Cast[A, B]](a)
I'm getting only Nones, meaning the types are never being seen as the same:
val mc: Option[Char] = cast('a') // None
val mb: Option[Boolean] = cast('a') // None
val mb2: Option[Boolean] = cast(true) // None
The same happens even when I'm being explicit with the types:
val mc: Option[Char] = cast[Char, Char]('a') // None
val mb: Option[Boolean] = cast[Char, Boolean]('a') // None
val mb2: Option[Boolean] = cast[Boolean, Boolean](true) // None
I'm using scala 3.2. Is there any way to achieve this cast function with the less verbose ergonomics? I'm even more curious why what I have isn't working, especially with the explicit casting? I'm pretty sure shapeless is able to provide an SYB implementation in scala 2, albeit probably relying on macros. Can we do this in scala 3 without macros?
You missed an implicit parameter
def cast[A, B](a: A)(using Cast[A, B]): Option[B] = summon[Cast[A, B]](a)
// ^^^^^^^^^^^^^^^^
When doing implicit resolution with type parameters, why does val placement matter? (implicitly[X] vs. (implicit x: X) in Scala 2, summon[X] vs. (using X) in Scala 3)

Understanding Mixed Context Bounds of Seq[AnyVal] and Seq[String]

Suppose I have some function that should take a sequence of Ints or a sequence of Strings.
My attempt:
object Example extends App {
import scala.util.Random
val rand: Random.type = scala.util.Random
// raw data
val x = Seq(1, 2, 3, 4, 5).map(e => e + rand.nextDouble())
val y = Seq("chc", "asas")
def f1[T <: AnyVal](seq: Seq[T]) = {
println(seq(0))
}
// this works fine as expected
f1(x)
// how can i combine
f1(y)
}
How can I add this to also work with strings?
If I change the method signature to:
def f1[T <: AnyVal:String](seq: Seq[T])
But this won't work.
Is there a way to impose my required constraint on the types elegantly?
Note the difference between an upper bound
A <: C
and a context bound
A : C
so type parameter clause [T <: AnyVal : String] does not make much sense. Also types such as String are rarely (or never) used as context bounds.
Here is a typeclass approach
trait EitherStringOrAnyVal[T]
object EitherStringOrAnyVal {
implicit val str: EitherStringOrAnyVal[String] = new EitherStringOrAnyVal[String] {}
implicit def aval[T <: AnyVal]: EitherStringOrAnyVal[T] = new EitherStringOrAnyVal[T] {}
}
def f1[T: EitherStringOrAnyVal](seq: Seq[T]): Unit = {
println(seq(0))
}
f1(Seq(1)) // ok
f1(Seq("a")) // ok
f1(Seq(Seq(1))) // nok
or generelized type constraints approach
object Foo {
private def impl[T](seq: Seq[T]): Unit = {
println(seq(0))
}
def f1[T](seq: Seq[T])(implicit ev: T =:= String): Unit = impl(seq)
def f1[T <: AnyVal](seq: Seq[T]): Unit = impl(seq)
}
import Foo._
f1(Seq(1)) // ok
f1(Seq("a")) // ok
f1(Seq(Seq(1))) // nok
I feel like you should write a separate function for both, but there are other ways to do it:
In Dotty, you can just use union types, which is what I'd recommend here:
Edit: As per Alexey Romanov’s suggestion, replaced Seq[AnyVal | String] with Seq[AnyVal | String], which was wrong,
def foo(seq: Seq[AnyVal] | Seq[String]): Unit = {
println(seq)
}
Scastie
If you're not using Dotty, you can still do this in Scala 2 with a couple reusable implicit defs
class Or[A, B]
implicit def orA[A, B](implicit ev: A): Or[A, B] = new Or
implicit def orB[A, B](implicit ev: B): Or[A, B] = new Or
def foo[T](seq: Seq[T])(implicit ev: Or[T <:< AnyVal, T =:= String]): Unit =
println(seq)
foo(Seq("baz", "waldo"))
foo(Seq(23, 34))
foo(Seq(List(), List())) //This last one fails
Scastie
You can also do it with a typeclass, as Luis Miguel Mejía Suárez suggested, but I wouldn't recommend it for such a trivial task since you still have to define 2 functions for each type, along with a trait, 2 implicit objects, and one function that can use instances of that trait. You probably don't want this pattern to handle just 2 different types.
sealed trait DoSomethingToIntOrString[T] {
def doSomething(t: Seq[T]): Unit
}
implicit object DoSomethingToAnyVal extends DoSomethingToAnyValOrString[AnyVal] {
def doSomething(is: Seq[AnyVal]): Unit = println(is)
}
implicit object DoSomethingToString extends DoSomethingToIntOrString[String] {
def doSomething(ss: Seq[String]): Unit = println(ss)
}
def foo[T](t: Seq[T])(implicit dsis: DoSomethingToIntOrString[T]): Unit = {
dsis.doSomething(t)
}
foo(Seq("foo", "bar"))
foo(Seq(1, 2))
In Scastie
def f1( seq: Seq[Any] ): Unit =
println( seq( 0 ) )
This works, because the least common supertype of Int and String (the 'lowest' type that is a supertype of both) would be Any, since Int is a subtype of AnyVal (i.e. 'the primitives) and String is a subtype of AnyRef (i.e. `the heap objects). f1 does not depends in any way on the contents of the list and is not polymorphic in its return type (Unit), so we don't need a type parameter at all.

Collect instances via LiftAll

I'm trying to describe the types which a case class contains.
import shapeless._
import shapeless.ops.hlist.LiftAll
trait Desc[T] {
def description: String
}
case class Foo(f: Int)
object Foo {
implicit val description: Desc[Foo] = new Desc[Foo] { val description = "foo" }
}
case class SomeCaseClass(f: Foo)
val gen = Generic[SomeCaseClass]
val lifted = implicitly[LiftAll[Desc, gen.Repr]].instances.toList
Gives me
could not find implicit value for parameter toTraversableAux: shapeless.ops.hlist.ToTraversable.Aux[shapeless.ops.hlist.LiftAll[Playground.this.Desc,Playground.this.gen.Repr]#Out,List,Lub]
not enough arguments for method toList: (implicit toTraversableAux: shapeless.ops.hlist.ToTraversable.Aux[shapeless.ops.hlist.LiftAll[Playground.this.Desc,Playground.this.gen.Repr]#Out,List,Lub])toTraversableAux.Out.
Unspecified value parameter toTraversableAux.
Scastie here: https://scastie.scala-lang.org/bXu71pMQQzCqrrsahVBkWA
When you summon an implicit instance with implicitly[LiftAll[Desc, gen.Repr]] then the dependent type Out of LiftAll is lost, so the compiler doesn't know which type exactly instances will return.
To work around this problem most typeclasses in Shapeless define an apply method in their companion object which does retain all dependent type information. It's the reason that you can use gen.Repr in a meaningful way after calling val gen = Generic[SomeCaseClass]. For some reason however LiftAll.apply was not implemented in this way. So that leaves you the option of implementing your own implicitly, or since you're using Shapeless anyway, use its the which is supposed to be a better implicitly.
scala> def impl[T <: AnyRef](implicit ev: T): ev.type = ev
impl: [T <: AnyRef](implicit ev: T)ev.type
scala> impl[LiftAll[Desc, gen.Repr]].instances.toList
res1: List[Desc[Foo]] = List(Foo$$anon$1#40b3708a)
scala> the[LiftAll[Desc, gen.Repr]].instances.toList
res2: List[Desc[Foo]] = List(Foo$$anon$1#40b3708a)
You can see the difference here in the inferred types that the REPL displays:
scala> impl[LiftAll[Desc, gen.Repr]]
res3: LiftAll.Aux[Desc,Foo :: HNil,Desc[Foo] :: HNil] = shapeless.ops.hlist$LiftAll$$anon$206#384d060c
scala> implicitly[LiftAll[Desc, gen.Repr]]
res4: LiftAll[Desc,gen.Repr] = shapeless.ops.hlist$LiftAll$$anon$206#30787774

Scala - restrict generic type to anything other than Future

I have a couple of methods on a trait as so:
trait ResourceFactory[+R] {
def using[T](work: R => T): T
def usingAsync[T](work: R => Future[T]): Future[T]
}
Unfortunately there's nothing in the type checker to stop you calling the first using method with a function returning a Future. I'd like the compiler to insist that the type of T in the first method be anything other than Future, to prevent that mistake - is that possible?
Thanks
You can use shapeless' <:!<:
import scala.concurrent.Future
import shapeless._
trait ResourceFactory[+R] {
def using[T](work: R => T)(implicit ev: T <:!< Future[_]): T = ???
def usingAsync[T](work: R => Future[T]): Future[T] = ???
}
Then:
scala> val r = new ResourceFactory[Int] {}
r: ResourceFactory[Int] = $anon$1#effe6ad
// Compiles (the error is due to the use of ???)
scala> r.using(_.toString)
scala.NotImplementedError: an implementation is missing
// Doesn't compile
scala> r.using(Future.successful(_))
<console>:17: error: ambiguous implicit values:
both method nsubAmbig1 in package shapeless of type [A, B >: A]=> shapeless.<:!<[A,B]
and method nsubAmbig2 in package shapeless of type [A, B >: A]=> shapeless.<:!<[A,B]
match expected type shapeless.<:!<[scala.concurrent.Future[Int],scala.concurrent.Future[_]]
r.using(Future.successful(_))
Here's an alternative I've stolen shamelessly from https://github.com/japgolly/scalajs-react/blob/cb75721e3bbd0033ad63d380bcaddc96fbe906e3/core/src/main/scala/japgolly/scalajs/react/Callback.scala#L21-L31:
#implicitNotFound("You're returning a ${A}, which is asynchronous, which means the resource may be closed before you try and use it. Instead use usingAsync.")
final class NotFuture[A] private[ResourceFactoryTests]()
object NotFuture {
final class Proof[A] private[ResourceFactory]()
object Proof {
implicit def preventFuture1[A]: Proof[Future[A]] = ???
implicit def preventFuture2[A]: Proof[Future[A]] = ???
#inline implicit def allowAnythingElse[A]: Proof[A] = null
}
#inline implicit def apply[A: Proof]: NotFuture[A] = null
}
which can be used as:
trait ResourceFactory[+R] {
def using[T: ResourceGuard](work: R => T): T
def usingAsync[T](work: R => Future[T]): Future[T]
}
This has the advantage of not having to add the implicit arg every time you implement the method, but the disadvantage that I'm pure cargo culting - I don't understand why it works, though it seems to use similar principles to shapeless.

How to convert a List[A] into a List[B] using an implicit conversion

I have the following use case which occurs often in my code:
A Collection[A]
An implicit conversion A to B
and I want to obtain a collection of B. I can use implicitly like the following:
case class Items(underlying:List[B])
import B._
def apply(a:List[A]):Items = {
val listOfB= a.map {implicitly[A=>B]}
Items(listOfB)
}
What is the most elegant way to do that in Scala, maybe with the help of Scalaz of doing the same?
Edit: the goal of my question is to find an idiomatic way, a common approach among libraries/developers. In such a sense developing my own pimp-my-library solution is something I dislike, because other people writing my code would not know the existence of this conversion and would not use it, and they will rewrite their own. I favour using a library approach for this common functions and that's why I am wondering whether in Scalaz it exists such a feature.
It's pretty straightforward if you know the types. First implicit conversion from A to B:
implicit def conversion(a: A): B = //...
then you need implicit conversion from List[S] to List[T] where S and T are arbitrary types for which implicit conversion from S to T exists:
implicit def convList[S, T](input: List[S])(implicit c: S => T): List[T] =
input map c
This should then work:
val listOfA: List[A] = //...
val listOfB: List[B] = listOfA
which is resolved by the compiler to:
val listOfB: List[B] = convList(listOfA)(conversion)
where S is A and T is B.
I wouldn't use an implicit conversion here, but a view bound in the class:
case class Foo(x: Int)
case class Bar(y: Int)
implicit def foo2Bar(foo: Foo) = Bar(foo.x)
case class Items[A <% Bar](xs: List[A]) {
def apply(x: Int): Bar = xs(x)
}
You can now create an instance of Items with a list of Foo and internally use them, as if they were Bars.
scala> Items(List(Foo(1)))
res8: Items[Foo] = Items(List(Foo(1)))
scala> res8(0)
res9: Bar = Bar(1)
edit:
Some clarification, on why I would not use an implicit conversion:
Implicit conversions can be dangerous, when they are in scope and accidentally convert things, that they shouldn't convert. I would always convert stuff explicitly or via view bounds, because then I can control it, also implicit conversion may shrink the size of your code, but also makes it harder to understand for others. I would only use implicit conversion for the 'extend my library' pattern.
edit2:
You could however add a method to the collection types, that does this conversion, if such a method is in scope:
trait Convertable[M[A], A] {
def convertTo[B](implicit f: A => B): M[B]
}
implicit def list2Convertable[A](xs: List[A]) = new Convertable[List, A] {
def convertTo[B](implicit f: A => B) = xs.map(f)
}
scala> implicit def int2String(x: Int) = x.toString
int2String: (x: Int)String
scala> List(1,2,3).convertTo[String]
res0: List[String] = List(1, 2, 3)
Instead of using another implicit conversion here, I would probably use a typeclass instead, but I think you get the basic idea.
Works starting with Scala 2.10:
implicit class ListOf[A](val list: List[A]) {
def of[B](implicit f: A => B): List[B] = list map f
}
implicit def int2String(i: Int) = i.toString
// Usage
List(1,2,3).of[String]
In my code, I'm using a more general version adapted from Tomasz' solution above which handles all Traversable instances
/** Implicit conversion for Traversable instances where the elements are convertable */
implicit def convTrav[S, T, I[S] <: Traversable[S]](input: I[S])(implicit c: S => T): I[T] =
(input map c).asInstanceOf[I[T]]
(This is working for me, although I'm keen to know if any more experienced Scala programmers think this is a bad idea for any reason, apart from the usual caveats about implicit conversions)