user5127720
user5127720

Reputation: 13

What do these lines mean (Scala / JavaTokenParsers)?

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

Answers (3)

Peter Neyens
Peter Neyens

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 Ls are never calculated, which improves the performance.

case "multiply first with 5" => 
  (u1:L, u2:L) => () => u1() * 5L // u2 is never executed

Upvotes: 3

Archeg
Archeg

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

ka4eli
ka4eli

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

Related Questions