F#: More return points in functions, how to handle them?
Asked Answered
V

3

6

I have a problem when returning values in complex functions. Examples are always better:

Consider the following function:

let myf (mypar: int) =
   mypar + 1

Well no probel here, this function is compiled correctly and the signature is:

val myf: int -> int

OK, well. Now consider this code:

let myf (mypar: int) =
   if mypar = 2 then
      4 (* ERROR *)
   mypar + 1

This does not work:

This expression was expected to have type unit but here has int

This error is raised everytime I try to return from my function when I am inside a if, a while a for or every other block. I thought that the problem was assuring that all possible return paths return the same type, but here I do not understand what happens.

Please note that if I insert a () unit everything works for example:

let myf (mypar: int) =
   if mypar = 2 then
      () (* No error *)
   mypar + 1

But that unit does not make my function return!!! it continues!!! Furthermore, could you please explain me how F# handles this???

Thankyou

Vesting answered 21/2, 2011 at 16:25 Comment(1)
Related post - Multiple Exits From F# FunctionRepetition
A
16

To add some more details, the problem with your approach is that everything in F# is an expression. This makes it a lot easier to reason about your programs (because you don't need to keep track of the currently executing statement), but it means that you always have to write a complete expression.

If you try to write something like return, it would be as if you wrote the following in C# (This probably explains why F# doesn't allow this kind of things):

int a = 10 + (3 * (return 10; 2));
return a;

Why didn't you get error when you wrote if .. then ()? The () expression creates a value of type unit that is special, because it has only one valid value. F# allows you to write if .. then without else when returning unit, because it can figure out that the else branch has to return the only existing unit value, so it sees your code as:

if something then ()
else () // implicitly added by the compiler

The only difference is throwing an exception (using raise) which behaves just like in C#. You could break out of a function using exception, but it is much better idea to rewrite the code to have a complete valid expression.

Amplifier answered 21/2, 2011 at 16:37 Comment(0)
F
10

F# has no return statement. The only way to do what you want to here, to choose either one block or the other, is with if .. else:

let myf (mypar: int) =
   if mypar = 2 then
      4
   else
      mypar + 1

Alternatively, throwing an exception exits the function early:

let myf (mypar: int) =
   if mypar = 2 then
      failwith "invalid argument"

   mypar + 1
Floodlight answered 21/2, 2011 at 16:29 Comment(2)
yes it works but my problem, generally speaking is that also in nested while or other if I cannot return... Should I use workflows?????Vesting
No. You should instead write your loop as a recursive function.Seringapatam
K
4

Have you tried using an else instead?

let myf (mypar: int) =
   if mypar = 2 then
      4
   else
      mypar + 1

I haven't tried it myself, but it's worth a shot :)

(Also consider using pattern matching instead, of course.)

Krishna answered 21/2, 2011 at 16:29 Comment(2)
What's Package matching? You mean pattern matching?Akihito
@nyinyithann: Absolutely - that's what I get for posting just as I'm leaving work :)Krishna

© 2022 - 2024 — McMap. All rights reserved.