Function taking another function of arbitrary arity as argument
Asked Answered
B

2

1

I have a series of functions that accept a function as an argument (func), and the only difference in them is that func accepts different numbers of parameters.

  def tryGet[T,A](func: (A) => T)
  def tryGet[T,A,B](func: (A,B) => T)
  ...       [T,A,B,C...]

Is there a way to make a function accept a function with any length argument list?

I tried using variable length argument lists, eg func:(A*) but had trouble passing any functions in as it now requires a Seq[A].

Brussels answered 18/9, 2019 at 14:3 Comment(5)
If you do not know the number and type of the arguments of the function. How do you expect to call / use it?Dejecta
@LuisMiguelMejíaSuárez I had expected to be able to call like so: func(). For example if I wanted to pass in the function def getSomething(int:Int) = Future.successful(int), by calling tryGet like so tryGet( (int:Int) => getSomething(int) ) I was using func() map { ... handle exceptions and return an Option instead}. The wider question i'm trying to solve is can I wrap a load of API calls that throw exceptions, so that they throw Options instead in the case of NoSuchElementExceptions.Brussels
Eg tryGet shouldn't know or care what the function is, it only knows that if func throws some specific exceptions it should return None, and if it doesn't then it should return Some(T)Brussels
How do you expect func() to compile? If it may take any number of arguments? You do not really want to pass any kind of function. But rather any kind o block that results on Future[T] and call something over it. Something like def tryGet[T](block: => Future[T]): Future[Option[T]] = block.recoverWith(...).Dejecta
Other alternative would be to just receive a function A => T where A is any kind of product. Thus, if you need two arguments, you pass them as a tuple.Dejecta
A
4

You can try to use shapeless.ops.function.FnToProduct

def tryGet[F: FnToProduct](func: F) = ???

val f1: Int => String = ???
val f2: (Int, Int) => String = ???
val f3: (Int, Int, Int) => String = ???

tryGet(f1)
tryGet(f2)
tryGet(f3)

https://github.com/milessabin/shapeless/wiki/Feature-overview:-shapeless-2.0.0#facilities-for-abstracting-over-arity

Arrogant answered 18/9, 2019 at 14:25 Comment(0)
V
1

Why don't you just use scala.util.Try? Or simply pass the argument to tryGet not as a block but as a by-name parameter of type T?

Vivianviviana answered 18/9, 2019 at 17:18 Comment(2)
Thanks but I don't know how to do that, an example would be great!Brussels
Try(unaryFunc(a)) Try(binaryFunc(a, b)).toOption or, if you wish to do it all manually, def tryGet[T](func: => T) = try { Some(func) } catch { case ex: Exception => None }Vivianviviana

© 2022 - 2024 — McMap. All rights reserved.