5

I have the following situation:

let private runStatement (vars : Map<identifier, value>) stmt =
    match stmt with
    | Assignment (id, expr) -> runAssignment vars id expr
    | Print exprs -> runPrint vars exprs
    | Read id -> runRead vars id
    | If (cond, stmts) -> runIf vars cond stmts

let rec private runStatements vars stmts =
    match stmts with
    | stmt::rest ->
        let newVars = runStatement vars stmt
        runStatements newVars rest
    | [] -> vars

let private runIf vars conditionalValue statements =
    match conditionalValue with
    | Boolean v when v -> runStatements vars statements
    | Boolean v -> vars
    | _ -> failwith "Not a boolean expression in if statement"

As you can see, function runStatement calls runIf, and runIf calls runStatement, because an if-statement is formed by some general statements, and a general statement can be an if-statement.

How can I solve this situation?

PS.: I have similar situations with other functions like runWhile, runIfElse et cetera.

Guy Coder
  • 24,501
  • 8
  • 71
  • 136
Gabriel
  • 1,922
  • 2
  • 19
  • 37
  • 2
    Please always include all code (types, functions, `open` statements) required to make the example compile. That allows others to focus on providing a solution without first having to fix the code. – TeaDrivenDev Jun 07 '16 at 23:46
  • 2
    Pass the functions in as arguments instead of coupling to them. – Mark Seemann Jun 08 '16 at 05:27
  • As a side note: I take it this is part of your compiler project since you used the tag `compiler-construction`. You should drop the `run` from the function names because people use to working with parsers expect the name of the function to be the same as the term they are parsing. So for this the terms are `statement`, `statements`, and `if`. I know you will get an error if you name a function `if` so what I would do is to name it `ifParser`, but not use run and that leads me to believe that it is a function that can be called from the main program and while that is possible is not custom. – Guy Coder Jun 08 '16 at 13:06
  • @TeaDrivenDev, the accepted answer contains a piece of code that reproduces my problem integrally, so now maybe I don't need include more code in my question anymore. – Gabriel Jun 09 '16 at 11:17
  • @GuyCoder, you are right, this is part of my compiler project. This code is from my `Interpreter` module, it takes an AST genereted by my parser and interprets it. – Gabriel Jun 09 '16 at 11:21
  • Ahh. I see why you have run now. As I don't know exactly how you structured your AST so this may not be correct, however walking the AST is typically how one interprets the AST. e.g. instead of having functions that call other functions, you walk the AST and as you visit each node you interpret what that node is to do. See: [AST interpreter?](http://stackoverflow.com/questions/10554998/ast-interpreter) Also I view answers by Ira Baxter for compilers in the same light as F# answers by Tomas. – Guy Coder Jun 09 '16 at 11:39
  • Also take a look at: [Arithmetic Expression Evaluation using Reverse Polish Notation (RPN)](http://stackoverflow.com/a/20785742/1243762) – Guy Coder Jun 09 '16 at 11:39
  • When the interpreter got done, I'll post it in codereview.stackexchange.com, and I would appreciate an review by you @GuyCoder. – Gabriel Jun 09 '16 at 12:03

1 Answers1

8

Use the 'and' keyword

let rec runx () = 
    printf "runx"
    runy ()
and runy () =
    printf "runy"
    runx ()

runx () |> ignore 

prints

runxrunyrunxrunyrunxrunyrunxrunyrunxrunyrunxrunyrunxrunyrunxrunyrunxrunyrunxrunyrunxruny
Phillip Scott Givens
  • 5,256
  • 4
  • 32
  • 54
  • Phillip, you are right, this the solution for my question. -- As a side note: After reviewing my code I've noticed that my language has left recursion and that's why I'm facing this kind of problem. I will refactor my language to remove this left recursion. (I'm saying it because it can help others). – Gabriel Jun 09 '16 at 11:14