简体   繁体   中英

How to map a function over the HList of functions from a certain type to some type?

For simplicity sake let's assume my HList instance holds exactly 2 values:

def intToString(x: Int) = x + "_"
def intToDouble(x: Int) = x * 10d
val fns = (intToString _ :: intToDouble _ :: HNil)

Now I'd like, having some Hlist of ints, to be able to do this:

(fns zip (1 :: 2 :: HList) map {case (f, x) => f(x) }

to get

("1_", 10.0)

From now on, assume that I don't know what I am doing and I totally understand all my paltriness in the faces of the functional gods.

I already looked at shapeless' wiki and, as far as I understood, I should make a function from Int to T that can be accepted by shapeless. Did I understood correct? Here's what I got:

object mapApply extends Poly1 {
  implicit def default[T] = at[Function[Int,T]](f => f.apply _)
}

At this point I'm completely lost and don't even have a clue of how to proceed. But I'm kinda fascinated by the potential power and expressiveness that this could deliver, so I'd really like to understand how this stuff works. I would really appreciate if your answers will not be just code snippets but rather more open and explanatory.

PS SO's engine just suggested me a c++ tag. Did I say something C++-ish?

It looks like you're mixing method and function definition syntax—I'll assume you meant something like the following:

val intToString = (x: Int) => x + "_"
val intToDouble = (x: Int) => x * 10d
val fns = intToString :: intToDouble :: HNil

Now you can use zipApply , which just pairs functions and their arguments:

val res = fns.zipApply(1 :: 2 :: HNil)

If for some reason zipApply didn't exist, you could accomplish the same thing with a Poly1 :

object apply extends Poly1 {
  implicit def default[I, O]: Case.Aux[(I => O, I), O] =
    at[(I => O, I)] { case (f, x) => f(x) }
}

val res = fns.zip(1 :: 2 :: HNil).map(apply)

Or this, if you don't want the extra genericity:

object applyToInt extends Poly1 {
  implicit def default[T]: Case.Aux[(Int => T, Int), T] =
    at[(Int => T, Int)] { case (f, x) => f(x) }
}

So you weren't too far off—you just needed to have a case in your Poly1 for the pair of the function and the argument, not just the function.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM