Reputation: 13
I am trying to better understand how to do mass parsing/interpreting.
I am having difficulty understanding lines like these:
type L = () => Long
And then later there are other lines like
val term = chainl1(myNum, "[*/]".r ^^ {
case "*" => (u1:L, u2:L) => () => u1() * u2()
case "/" => (u1:L, u2:L) => () => u1() / u2()
})
I am just trying to understand the underlying structure here. What exactly is ()
here? What is the logical flow of these val
statements?
I assume this means "if we find *
or /
in myNum
, match on these two cases depending on which one it is, and then... long flow of logic I don't understand"
Upvotes: 1
Views: 108
Reputation: 9820
The answer of ka4ell is correct, but does not mention why you would use () => Long
instead of just using Long
: with () => Long
or L
the execution of the calculation which returns the Long
is delayed. We only execute the functions at the moment we want the actual result, this is called lazy evaluation.
In your case:
case "*" =>
// Return a function which takes two Ls : u1 and u2
// and which returns an L : () => u1() * u2()
(u1:L, u2:L) => () => u1() * u2()
Let's define a simple function which returns an L
:
// return a function which will return a Long
// this could potentially be a very expensive calculation
def giveMeAnL(n: Long) = () => {
println("giveMeAnL is called")
n
}
If we would use an analogous function than the one in the case:
// analogous case "*" => ...
def multiply(u1:L, u2:L) = () => {
println("multiply is called")
u1() * u2()
}
// create two Ls
val (l1, l2) = (giveMeAnL(5L), giveMeAnL(2L))
val productL = multiply(l1, l2) // productL is of type L
The value productL
now contains an L
which can calculate the product of the two values. At this point, neither the product nor the two values are calculated. If we call the productL
value, the two values are calculated and the product of these values is calculated.
val product = productL()
// multiply is called
// giveMeAnL is called
// giveMeAnL is called
// product: Long = 10
If somewhere in your parsing steps, you want to ignore some L
values, the results of these L
s are never calculated, which improves the performance.
case "multiply first with 5" =>
(u1:L, u2:L) => () => u1() * 5L // u2 is never executed
Upvotes: 3
Reputation: 8462
If we split the line case "*" => (u1:L, u2:L) => () => u1() * u2()
:
case "*" =>
means match *
to the code that is written next
(u1:L, u2:L) => {}
is a definition of function that has two arguments of type L
u1
and u2
are functions, because their type is L
, and it is actually () => Long
which means this is a function that takes nothing and returns Long
() => u1() * u2()
is a function with no arguments, that calls u1
and u2
and multiplies their results
Going back:
(u1:L, u2:L) => () => u1() * u2()
is a function of two arguments which returns a function of no arguments, that executes both arguments of a first function, multiplies them and return the result
So, () =>
means a function with no arguments. The only exception here is case * =>
where =>
doesn't belong to a function, but rather to match statement
Upvotes: 0
Reputation: 5424
type L = () => Long
describes a function with zero arguments and return type Long. For example
def someConstant() = 5L
Here someConstant
is of type L
.
This line
case "*" => (u1:L, u2:L) => () => u1() * u2()
will return you a function of type Function2
(arity 2) with return type Function0
(arity 0) which when is called will return the result of u1() * u2()
.
val f = () => (x:Int) => x
can be written as
() => ((x: Int) => x)
Here f is a function with arity 0 which when is called returns another function with arity 1 which accepts Int argument and returns it when called.
f()(6) == 6
is true statement.
Upvotes: 4