Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Shapeless : Prepend. Implicit not found

I'm trying to use shapeless to accumulate easily objects in a type safe manner.

The problem is when I want to concat (:::) two HList. I'm encountering a newbie (it seems at least) problem. It misses a Prepend implicit instance in the context.

However, looking into hlist.scala, I can see that generic implicit def are defined in the objects Prepend and PrependAux.

Adding import Prepend and import PrependAux manually didn't change anything (obviously...).

So here the code reduced to the minimum:

enter code here

import shapeless._
import HList._
import Prepend._
import PrependAux._

object test {

  val a:HList = 1 :: 4 :: "A" :: HNil
  val b:HList = "R" :: false :: HNil

  val c:HList = a ::: b   // <<<<<<<<<<< NEEDS A Prepend in the context 

}

In the console now:

[error]     test.scala:10: could not find implicit value for parameter prepend: shapeless.Prepend[shapeless.HList,shapeless.HList]
[error]     val c:HList = a ::: b   // this needs an implicit Prepend in the current context

What should burn my eyes?

thanks

EDIT

A little update to re-complexify a bit the real problem, because to vulgarization was to strong before.

Here is the kind of thing that I would be able to do:

case class A[L<:HList](a:L) { 
  def doSmth[C <:HList](c:C) = a ::: c 
}

So I've not the access to the real type, only I know that they are HList s.

like image 290
Andy Petrella Avatar asked Jun 14 '12 15:06

Andy Petrella


1 Answers

The up-casts to HList are the problem here. There's almost nothing you can do with a plain old HList (apart from adding new elements to it).

You can either provide more informative type annotations:

val a: Int :: Int :: String :: HNil = 1 :: 4 :: "A" :: HNil
val b: String :: Boolean :: HNil = "R" :: false :: HNil
val c: Int :: Int :: String :: String :: Boolean :: HNil = a ::: b

Or just let the types be inferred, which is usually much more convenient:

val a = 1 :: 4 :: "A" :: HNil
val b = "R" :: false :: HNil
val c = a ::: b

In response to your comment: you can do what you want if you make sure you've got the evidence you need (note that I've assumed that a: A was a typo for a: L, and that you'll need -Ydependent-method-types for this to work):

case class A[L <: HList](a: L) {
  def doSmth[C <: HList](c: C)(implicit p: Prepend[L, C]) = a ::: c
}

In general you can just look at the implicits that are necessary for the operations you're using, and then include them on your method.

like image 183
Travis Brown Avatar answered Sep 20 '22 17:09

Travis Brown