Can I pass an arbitrary function to another function in Scala?

I'm new to Scala, and being able to pass functions to other functions is pretty neat - but can I pass an arbitrary function link to another function? The arity of the mentioned functional parameter will be fixed (this suggests that I also wonder if you can also pass a function with arbitrary arity). I keep getting upset about type errors. I tried using Any , but it doesn't seem to help.

For example, I have the code below:

 class CodeRunner(val user_defined: (Int) => Unit) { def run(input: Int) = { user_defined(input) } } def arbitrary_code(input: Int) = { println("Running with input " + input) } val d1 = new CodeRunner(arbitrary_code) d1.run(4) 

And I get:

 Running with input 4 

Now let's say that I want to pass the following function:

 def arbitrary_code(input: String) = { println("Running with input " + input) } 

How can I change the CodeRunner class to handle both?

+7
source share
5 answers

Generic types allow you to define a class with a placeholder type that is specified when instantiating an object. The compiler is happy because it can make sure everything is type safe, and you are happy because you can instantiate an object and pass arbitrary types for the value.

To use a generic type with your class, you can change it as follows:

 class CodeRunner[T] (val user_defined: (T) => Unit) { def run(input: T) = { user_defined(input) } } 

[T] after "class CodeRunner" is the important part - it determines that there is a general type T (you could replace T with a different capital letter, etc.) that will be used in the class definition.

So, if you define a method:

 def arbitrary_code(input: String) = { println("Running with input " + input) } 

and then pass it:

 val d1 = new CodeRunner(arbitrary_code) 

... the compiler then says: "aha, for this CodeRunner instance, the generic type T is a string." And if you call

 d1.run("string") 

the compiler will be happy, but will not let you go through d1.run (4).

+3
source

How can I change the CodeRunner class to handle both?

You can make an arbitrary type a class parameter:

 class CodeRunner[T](val user_defined: (T) => Unit) { def run(input: T) = { user_defined(input) } } def arbitrary_code(input: Int) = { println("Running with input " + input) } val d1 = new CodeRunner(arbitrary_code) d1.run(4) def arbitrary_code2(input: String) = { println("Running with input " + input) } val d2 = new CodeRunner(arbitrary_code2) d2.run("hello") 

Note that the type of d2 is CodeRunner[String] , which is not assigned to d1 , which is equal to CodeRunner[Int] .

+9
source

To pass an arbitrary function, you can, of course, use generics:

 def run[T,U](f: T => U) = println(f) 

For arbitrary arity this is impossible, because a function of type T => U is an instance of Function1 [U, T], and a function of type (T, U) => V is an instance of Function2 [T, U, V]. (Also, I could not find a useful use case). However, there is a clever concept called "currying". It consists in converting a function that takes several arguments and returns a value in a function that takes one argument and returns another function. Here is an example:

 def nonCurriedAdd(x: Int, y: Int) = x + y // nonCurriedAdd(4,6) def curriedAdd(x: Int) = (y: Int) => x + y // we can use some syntax sugar def curriedAdd(x: Int)(y: Int) = x + y // curriedAdd(4)(6) 

So now you can do `d1.run (curriedAdd). You can also convert a non-curry function to curry using the "curried" method:

 d1.run(nonCurriedAdd.curried) 
+2
source

Can I pass an arbitrary function reference to another function? The arity of the specified function parameter will be fixed.

As always, write down the type of function you are developing, and everything becomes clear.

Your word "arbitrary" assumes that function arguments work on any type. That is, these are polymorphic functions (or common functions, in some languages).

The following should correctly translate to Scala:

 == The type of an "arbitrary" function of fixed arity f :: a -> b -> c -> d -- The type of a function that accepts such a -- function as an argument, and does something with it: g :: (a -> b -> c -> d) -> a -> b -> c -> d -- And a function that implements something of that type gfabc = fabc 

You may be able to come up with several other higher-order functions that perform functions of a fixed arity, but of an arbitrary (i.e., polymorphic) type and work on them.

Classical functions of a higher order, for example,

 map :: (a -> b) -> [a] -> [b] fold :: (a -> b -> b) -> b -> [a] -> b 

And many, many others.

+1
source
 scala> object codeRunner { | def run[InputType, OutputType](code: InputType => OutputType) = (input: InputType) => code(input) | } defined module codeRunner scala> def someCode(x: Int) { | println("This code uses " + x) | } someCode: (x: Int)Unit scala> def otherCode(y: String) { | println("This code uses " + y) | } otherCode: (y: String)Unit scala> codeRunner.run(someCode)(10) This code uses 10 scala> codeRunner.run(otherCode)("hello") This code uses "hello" 
0
source

All Articles