This is a function from a parser module. I have trouble understanding one line of code
let rec e1 tokens =
match tokens with
Tokenizer.IfTok :: tokens1 ->
let (testAST, tokens2) = e1 tokens1
in
(match tokens2 with
Tokenizer.ThenTok :: tokens3 ->
let (thenAST, tokens4) = e1 tokens3
in
(match tokens4 with
Tokenizer.ElseTok :: tokens5 ->
let (elseAST, tokens6) = e1 tokens5
in
(If(testAST, thenAST, elseAST), tokens6)
| _ -> raise (Syntax ("e1: missing else.")))
| _ -> raise (Syntax ("e1: missing then.")))
| _ -> e2 tokens
and e2 tokens = ........
I have no idea how this line works
let (testAST, tokens2) = e1 tokens1 in
I know it declares a local variable which is a tuple, but where does the value (testAST, tokens2) come from? It doesn’t seem to have anything to do with tokens or tokens1. Also does this line only declares a tuple or it also calls the function? Thanks!
Yes, this line does declare two variables and does call the function
e1, binding the variables to result of the function call.This way of binding variables is called pattern matching. It is based on information about the return type of function
e1– compiler knows it returns a tuple, and then it may be decomposed to parts, and these parts are bound to two new variables,testASTandtokens2. It is one of most powerful features of FP, which allows you to write much more readable, flexible and brief code.It may also be done (matched) on everything if the structure of that entity (pattern) is known to compiler (e.g. case classes in Scala, tuples and lists in Haskell, records in Erlang, etc). Also pattern matching may be used to ignore some parts of the structure that are not relevant for the conditions (e.g. in Haskell if you want to select the second item in three-tuple, just do
selectSecond (_, a, _) = a, where_is special symbol for ignoring values).