Passing a function as an argument in Scala / Figaro
I am trying to learn Figaro and since it is implemented in Scala I am running into some Scala problems. For example, the code below Importance.probability
takes two arguments, the first is the distribution and the second is the predicate. But when I try to run this code, I get the following error:
Missing argument for moreThan50
which makes sense since it actually takes one argument.
Since Scala is a functional language, I guess there is some clever standard way of sending functions as arguments that I missed? I tried to use _
to make it partially applied, but it doesn't work.
import com.cra.figaro.library.atomic.continuous.Uniform
import com.cra.figaro.algorithm.sampling.Importance
def greaterThan50(d: Double) = d > 50
val temperatur = Uniform(10,70)
Importance.probability(temperatur, greaterThan50)
source to share
Note that in Scala you can pass a value to a function like greaterThan50
where a function is expected.
In this case, in the method probability
that is defined as
def probability[T](target: Element[T], predicate: T => Boolean): Double
the second argument is a function, but why doesn't the compiler accept, when passed greaterThan50
, which is actually the function's value?
This is because Importance
there is another overloaded method that is defined below:
def probability[T](target: Element[T], value: T): Double
So when we call
Importance.probability(temperatur, greaterThan50)
the compiler does raise the seconds overload method. So it tries to use a method greaterThan50
on some value to get some result in the result that can be used as the second type argument T
.
In this case, to disambiguate, you need to partially apply the function :
Importance.probability(temperatur, greaterThan50 _)
which fixes the problem as the type greaterThan50 _
is now equal Double => Boolean
, which is an exact match for the first overloaded function.
Experiment to prove
To make sure this approach works in non-overloaded methods, you can simply try to define the following function in your context (for example in object
):
def probability[T](target: Element[T], predicate: T => Boolean): Double = 10
and call it
probability(temperatur, greaterThan50) // Note that this function is defined by you
you will see there is no compilation error as the compiler is expecting a function and you are giving it a function value.
Other options
You can of course pass the literal to the function in probability
:
Importance.probability[Double](temperatur, (x: Double) => x > 50)
or you can define greaterThan50
like this:
def greaterThan50 = (d: Double) => d > 50
which will be of type (Double) => Boolean
, which again is an exact match.
Renouncement
The figaro
version 2.4.0.0
with the Scala version is used 2.11.2
.
source to share
The reason this doesn't work is because you are calling a different method called probability
than the one you think you are calling.
You call the companion object method probability
that has this signature:
def probability[T](target: Element[T], value: T, numSamples: Int = 10000): Double
You probably want something like this:
import com.cra.figaro.library.atomic.continuous.Uniform
import com.cra.figaro.algorithm.sampling.Importance
def greaterThan50(d: Double) = d > 50
val temperatur = Uniform(10,70)
val alg = Importance(myNumSamples = 100, temperatur)
alg.start()
alg.probability(temperatur, greaterThan50 _)
Have a look at Hello World which uses Importance
.
source to share