Mark Bell
Mark Bell

Reputation: 29785

Why do I always get an empty list when I try to return the contents of a mutable list from this module?

Please, help an F# beginner understand this! I have the following F# code (which I've just created to help me learn, so I realise it's probably terrible):

type Account = {
    ID: Guid
    Name: string
};

module Accounts =
    let mutable accounts:Account list = []

    // Why does this always return empty?
    let lst =
        accounts

    let load id =
        accounts |> List.find(fun a-> a.ID = id)

    let save account =
        accounts <- account::accounts

Accounts.save { ID = Guid.NewGuid(); Name = "Account One"}

let id = Guid.NewGuid()

Accounts.save { ID = id; Name = "Account Two"}

let account = Accounts.load id

If I write out the value of account at this stage (after the above code), I see the Account record I expect (Account Two), and if I dump Accounts.accounts, I can see that the mutable list contains both Account records.

So why does Account.lst always return an empty list, even though I can see that the list definitely isn't empty?

Upvotes: 2

Views: 103

Answers (2)

Fyodor Soikin
Fyodor Soikin

Reputation: 80765

Because lst is a value, not a function.

In F#, the technical difference between a value and a function is that a function has parameters, and a value does not.

When you declared lst, you didn't give it any parameters, so the compiler understood it as "I want to take the value of accounts at this particular point in time, and refer to that value as lst from now on". So every time you write lst, you're not calling a function, but merely referring to that same empty list that was the value of accounts at initialization time.

To make lst a true function, you need to give it a parameter. And because it doesn't really need any actual data, the natural parameter to give it is the unit value - ().

let lst () = accounts

P.S. This whole trickiness ultimately comes from mutating state. Try to avoid it when possible.

Upvotes: 7

Ringil
Ringil

Reputation: 6537

Because lst is a value not a function. You need to convert it to a function:

let lst () =
    accounts

then you can call it by:

Accounts.lst()

Upvotes: 4

Related Questions