Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

F# match with mutable

Tags:

f#

Just started playing with F# and I want to create some mutable model inside my app to play with, using F# discriminated union instead of class hierarchy. However there seems no way to "downcast" a discriminated union and "match with" doesn't propagate mutability. What should I do?

type Foo = {
    mutable x: int
}

type FooBar = 
    | Foo of Foo
    | Bar

let f = {x = 2};
do f.x <- 3; //All ok

let fb = Foo {x = 1}
do match fb with
    | Foo {x = x} -> x <- 2 //"This value is not mutable"
    | Bar -> ()
like image 909
Dzugaru Avatar asked Feb 10 '23 23:02

Dzugaru


1 Answers

your problem is, that you match/deconstruct fb into a new pattern/value x : int (that is not the same as the f.x at all!) which will of course be immutable (as bindings/values in F# are by default).

you probably see this much better if you don't give both (the value and the pattern) the same name:

> match fb with Foo { x = y } -> y;;
val it : int = 1

see you match x against y so y will get the value of x (but will not be mutable)


situation in C#

let's look at what would be a similar situation in C#

assuming you have a Foo class:

class Foo { public int x { get; set; } }

and a FooBar base-class with

class Foo2 : FooBar 
{ 
    public Foo Value { get; } 
}

(I striped the ctors because I am to lazy - you get the idea)

now you would do this:

var fb = new Foo2(new Foo(1));
var x = fb.Value.x;
x := 2;

do you think that fb.Value.x will be 2 or 1? ;)


how to pattern-match / mutate

use

let fb = Foo {x = 1}
do match fb with
    | Foo f -> f.x <- 2
    | Bar -> ()

instead - this will deconstruct f out of fb and then you can set the mutable record-field f.x

But I would suggest not starting to learn F# by trying out how to use mutable values - try to learn using immutability as much as you can istead :)

like image 66
Random Dev Avatar answered Feb 15 '23 23:02

Random Dev