1

I want to make some function for unspecified number of arguments of function

for example

scala> def test(fx: (String*) => Boolean, arg: String*): Boolean = fx(arg: _*)
test: (fx: String* => Boolean, arg: String*)Boolean

scala> def AA(arg1: String, arg2: String) :Boolean = {
       println ("Arg1 : " + arg1 + " Arg2 : " + arg2)
       true}
AA: (arg1: String, arg2: String)Boolean

scala> test(AA,"ASDF","BBBB")
<console>:10: error: type mismatch;
 found   : (String, String) => Boolean
 required: String* => Boolean
            test(AA,"ASDF","BBBB")
                  ^

How can I solve this problem??

2
  • There are ways to solve this, but you do realize that it will mean that you can have errors at runtime when passing in args a different numbers of values that fx expects? Is that OK with you? Commented May 4, 2016 at 8:27
  • Also, can you be more specific on exactly what you are attempting to achieve? As it stands, your test method does nothing more than calling the passed function so it's hard to guess why you cannot directly call the function in the first place (and thus hard to propose any potentially saner alternative) Commented May 4, 2016 at 8:40

2 Answers 2

3

This could be done using shapeless with ProductArgs and something similar to my answer to another question.

import shapeless.{HList, ProductArgs}
import shapeless.ops.hlist.IsHCons
import shapeless.ops.function.FnToProduct
import shapeless.syntax.std.function._

object test extends ProductArgs {
  def applyProduct[L <: HList, NarrowArgs <: HList, Args <: HList, F, R](
    l: L
  )(implicit 
    ihc: IsHCons.Aux[L, F, NarrowArgs],
    ftp: FnToProduct.Aux[F, Args => R],
    ev: NarrowArgs <:< Args
  ): R = {
    val (func, args) = (l.head, l.tail)
    func.toProduct(args)
  }
}

Which you can use as :

def aa(s1: String) = s1.length
def bb(s1: String, s2: String) = s1 * s2.length

test(aa _, "foo")         // Int = 3
test(bb _, "foo", "bar")  // String = foofoofoo
// test(aa _, "foo", "bar") doesn't compile

Extending ProductArgs transforms or test(aa _, "foo") (which is actually test.apply(aa _, "foo")) to test.applyProduct((aa _) :: "foo" :: HNil). In applyProduct we check that the HList consists of a function and valid arguments.


We shouldn't need the NarrowArgs <:< Args, but ProductArgs seems to give the same result as SingletonProductArgs.

Sign up to request clarification or add additional context in comments.

2 Comments

That's nice, but it makes the explicit assumption that the function arity (in fact, even the exact signature) is fully know when calling test (or - admittedly- that we are OK to pass around shapeless type class instances along with the function, to make the call compile). And if that's the case, then what does test bring to the table besides directly calling said function (or passing a thunk to test that does it). I think it would be more productive if OP explained what's his use case exactly.
@RégisJean-Gilles you are right, test is actually not really useful.
0

It's because AA does not accept variable number of arguments, change it to:

def AA(args: String*) :Boolean

2 Comments

thanks. but I want to get all functions without reference to any number of parameters. if I have 2 functions like this def AA (arg: String) = println(arg) and def BB(arg1: String, arg2: String) = println(arg1 + arg2), and I want to pass it to test function as a parameter. test(AA,"HELLO") and test(BB,"HELLO","WORLD") is it possible??
I'm not sure if that's possible.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.