0

I've recently picked up F#, and am currently working on a command line utility to help automate some work related tasks. I have implemented a command parser, and a Union for my the different command options, and it all works fine.

When I get to the execution part depending on the options something seems to break though.

Lets say I have a module with 2 functions that I want to run depending on the result of the command input

module OptionRunner
let option1 a b = a + b
let option2 c d = c |> Seq.map(fun i-> i + d)

Now my determiner will look like:

let runCommands =
    if option.opt1 then
        option1
    else if options.opt2 then
        option2

This might be over-simplified, but hopefully gives a fair understanding of what I am trying to accomplish.

Now, my problem is that whatever I do in runCommands, and however many different functions I have in my OptionRunner module it ALWAYS calls option1, and then continues through the entire list of functions in that module.

I have even tried creating local modules for each function to test it. It still ALWAYS called option1.

I cannot see a difference between my indentation or module structure from this file to any other module in the project (where there are no problems)

Has anyone experienced and solved this? It's been driving me nuts.

max
  • 96,212
  • 14
  • 104
  • 165
Edgars
  • 11
  • 4

2 Answers2

0

It is hard to see what's going wrong without looking at your actual code. The most common reason for behavior like this is that you are actually defining unit values rather than functions that can be called. For example, if you had something like:

module Demo

let foo =
  printfn "foo"

let bar = 
  printfn "bar"

let run = 
  if false then foo
  elif false then bar
  else ()

Here, foo and bar are actually values that are evaluated when the module is initialized (and so the program always runs their bodies and prints "foo" and "bar"). The code inside run is not actually calling functions, it is just referring to already evaluated values.

To turn them into functions, you'd have to add some arguments:

let foo () =
  printfn "foo"

let bar () = 
  printfn "bar"

let run () = 
  if false then foo ()
  elif false then bar ()
  else ()

In your actual sample, it looks like you are actually defining functions (the definitions are correct), but your calling code looks like it is just referring to values. So I suspect that the problem is more complicated version of what I described.

Tomas Petricek
  • 240,744
  • 19
  • 378
  • 553
0

In F#, the execution order is actually very simple, it is top-down left-to-right. So it is perfectly to be expected, that your modules "run". The way, how you control evaluation is by making things lazy or functions where appropriate... E.g. if you say

let sum = a + b

that evaluates sum and sets it according to whatever a and b are. If you do not want sum to be evaluated immediately there, where you defined it, you might rather write something like

let sum a b = a + b

You have to be aware that the upper sum is a one single value. It is pretty much like a local variable for instance.

The lower sum is a function which takes two arguments. However, in both cases, the sum is evaluated just that the second one is "done" when your function is defined.

So when looking at your original problem, you most likely need to make option1 a function which takes a unit value () as input. And call it as option1().

Daniel Fabian
  • 3,828
  • 2
  • 19
  • 28