0

in F#, it's not allowed to have mutable argument with functions. but if I have a function like the following:


let f x =
    while x>0 do
      printfn "%d" x
      x <- x-1;;

when I compile this, I'm getting a compiler error.(not mutable) How would I fix this function?

null
  • 49
  • 6

3 Answers3

1

You could rewrite it like this:

let f x = [x.. -1..1] |> List.iter (printfn "%d")

If you want to keep the while loop, you could do this:

let f (x : byref<int>)=
    while x>0 do
        printfn "%d" x
        x <- x-1

let mutable x = 5
f &x
FRocha
  • 942
  • 7
  • 11
1

Depends on whether you want the final, mutated value of x to be passed back to the caller of the function or mutate it only locally.

For local-only mutation, just declare another variable, which would be mutable, but initially will have the value of x:

let f x =
    let mutable i = x
    while i>0 do
      printfn "%d" i
      i <- i-1

For passing the result back to the caller, you can use a ref-cell:

let f (x: int ref) =
    while x.Value>0 do
      printfn "%d" x.Value
      x := x.Value - 1

Note that now you have to refer to the ref-cell contents via the .Value property (or you can instead use operator !, as in x := !x - 1), and the mutation is now done via :=. Plus, the consumer of such function now has to create a ref-cell before passing it in:

let x = ref 5
f x
printfn "%d" x.Value  // prints "0"

Having said that, I must point out that mutation is generally less reliable, more error-prone than pure values. The normal way to write "loops" in pure functional programming is via recursion:

let rec f x = 
    if x > 0 then
        printf "%d" x
        f (x-1)

Here, each call to f makes another call to f with the value of x decreased by 1. This will have the same effect as the loop, but now there is no mutation, which means easier debugging and testing.

Fyodor Soikin
  • 78,590
  • 9
  • 125
  • 172
1

For pass-by-value semantics, you can use parameter shadowing.

Here, a shadowed (because it's the same name) mutable value x is declared on the stack.

let f x =
    let mutable x = x
    while x > 0 do
      printfn "%d" x
      x <- x - 1

For pass-by-reference semantics, you'll have to use a reference cell, which is a just a fancy way of passing an object which has a mutable field in it. It's similar to ref in C#:

let f x =
    while !x > 0 do
      printfn "%d" !x
      x := !x - 1

Using a reference cell:

let x = (ref 10)
f x
Debug.Assert(!x = 0)
Asti
  • 12,447
  • 29
  • 38