Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multiple Exits From F# Function

I could do this easily in C++ (note: I didn't test this for correctness--it's only to illustrate what I'm trying to do):

   const int BadParam = -1;
   const int Success = 0;

   int MyFunc(int param)
   {
      if(param < 0)
      {
         return BadParam;
      }

      //normal processing

      return Success;
   }

But I cannot figure out how to exit a routine early in F#. What I want to do is to exit the function on a bad input but continue if the input is ok. Am I missing some fundamental property of F# or am I approaching the problem in the wrong way since I'm just learning FP? Is a failwith my only option here?

This is what I've got so far and it compiles ok:

   #light

   module test1

       (* Define how many arguments we're expecting *)
       let maxArgs = 2;;
       (* The indices of the various arguments on the command line *)
       type ProgArguments =
           | SearchString = 0
           | FileSpec = 1;;

       (* Various errorlevels which the app can return and what they indicate *)
       type ProgReturn =
           | Success = 0
           | WrongNumberOfArgumentsPassed = 1;;

       [<EntryPoint>]
       let main (args:string[]) =

           printfn "args.Length is %d" args.Length

           let ProgExitCode = if args.Length <> maxArgs then
                                   printfn "Two arguments must be passed"
                                   int ProgReturn.WrongNumberOfArgumentsPassed
                                   (* Want to exit "main" here but how? *)
                               else
                                   int ProgReturn.Success

           let searchstring, filespec  = args.[int ProgArguments.SearchString],args.[int ProgArguments.FileSpec];

           printfn "searchstring is %s" searchstring
           printfn "filespec is %s" filespec

           ProgExitCode;;

Is there an FP way of dealing with this sort of thing?

like image 472
Onorio Catenacci Avatar asked Oct 22 '09 20:10

Onorio Catenacci


1 Answers

In my opinion, match expressions are the F# analogue of early-exit for calling out erroneous conditions and handling them separately. For your example, I'd write:

 [<EntryPoint>]
 let main (args:string[]) =
     printfn "args.Length is %d" args.Length
     match args with
     | [| searchstring; filespace |] -> 
       // much code here ...
       int Success
     | _ -> printfn "Two arguments must be passed"
       int WrongNumberOfArgumentsPassed

This separates the error case nicely. In general, if you need to exit from the middle of something, split functions and then put the error case in a match. There's really no limit to how small functions should be in a functional language.

As an aside, your use of discriminated unions as sets of integer constants is a little weird. If you like that idiom, be aware that you don't need to include the type name when referring to them.

like image 181
Nathan Shively-Sanders Avatar answered Oct 01 '22 13:10

Nathan Shively-Sanders