Why does the FSI not always give me the expected ‘it’ value?

Note: I have seen this with some code but not others so I’m confused at to when to expect it happening.

I have some basic code in an FSX script that I am experimenting with:

let hasBreachedTarget target total = if total >= target then true else false 

let report hasBreached total = 
    if total |> hasBreached then Ok total else Error total 

let loadUp target collection = 

    let hasBreachedTarget = hasBreachedTarget target 

    let report = report hasBreachedTarget

    let rec load acc collection = 
        match collection with 
        | [] -> report acc
        | [single] -> report (acc + single)
        | head::tail -> 
            let newTotal = acc + head 
            if newTotal |> hasBreachedTarget then
                report newTotal 
            else 
                load newTotal tail

    load 0 collection 

let result = [ 1; 5; 4; 3; 4; 5 ] |> loadUp 15

…which, when executed in the FSI via Ctrl+A and Alt+Enter, reports what I would expect:

val hasBreachedTarget: target: 'a -> total: 'a -> bool when 'a: comparison
val report: hasBreached: ('a -> bool) -> total: 'a -> Result<'a,'a>
val loadUp: target: int -> collection: int list -> Result<int,int>
val result: Result<int,int> = Ok 17

However, if I change the last bit of code to simply (without the ‘let result =’):

[ 1; 5; 4; 3; 4; 5 ] |> loadUp 15

… I get this result:

val hasBreachedTarget: target: 'a -> total: 'a -> bool when 'a: comparison
val report: hasBreached: ('a -> bool) -> total: 'a -> Result<'a,'a>
val loadUp: target: int -> collection: int list -> Result<int,int>

…with no ‘it’ value.
I thought the ‘it’ value was supposed to be the result of the last thing executed.

If I try something even simpler, like:

[ 1; 5; 4; 3; 4; 5 ] |> List.sum

…I get an ‘it’ value, but I don’t get ‘it’ with my code above.

Am I doing something wrong, or misinterpreting something?
Is it something to do with the recursive nature of the loadUp function?

Note: Microsoft (R) F# Interactive version 12.5.0.0 for F# 7.0

Wow, I wonder if that’s a regression??
I have F# Interactive version 12.4.0.0 for F# 7.0, and I get the it value:

> let hasBreachedTarget target total = if total >= target then true else false
-
- let report hasBreached total =
-     if total |> hasBreached then Ok total else Error total
-
- let loadUp target collection =
-
-     let hasBreachedTarget = hasBreachedTarget target
-
-     let report = report hasBreachedTarget
-
-     let rec load acc collection =
-         match collection with
-         | [] -> report acc
-         | [single] -> report (acc + single)
-         | head::tail ->
-             let newTotal = acc + head
-             if newTotal |> hasBreachedTarget then
-                 report newTotal
-             else
-                 load newTotal tail
-
-     load 0 collection
- [ 1; 5; 4; 3; 4; 5 ] |> loadUp 15;;
val hasBreachedTarget: target: 'a -> total: 'a -> bool when 'a: comparison
val report: hasBreached: ('a -> bool) -> total: 'a -> Result<'a,'a>
val loadUp: target: int -> collection: int list -> Result<int,int>
val it: Result<int,int> = Ok 17

This sort of thing has come up often for me but I don’t know if it’s just me that’s doing something wrong.

For instance, if I reset the FSI session (not pressing Enter in the FSI window) and then Ctrl+A and Alt+Enter the following code (same code as earlier):

let hasBreachedTarget target total = 
    if total >= target then true else false 

let report hasBreached total = 
    if total |> hasBreached then Ok total else Error total 

let loadUp target collection = 

    let hasBreachedTarget = hasBreachedTarget target 

    let report = report hasBreachedTarget

    let rec load acc collection = 
        match collection with 
        | [] -> 
            report acc
        | [single] -> 
            report (acc + single)
        | head::tail -> 
            let newTotal = acc + head 
            if newTotal |> hasBreachedTarget then
                report newTotal 
            else 
                tail |> load newTotal 

    collection |> load 0  

[ 1; 5; 4; 3; 4; 5 ] |> loadUp 15

…I get this as the output:

Welcome to F# Interactive for .NET Core in Visual Studio. To execute code, either
  1. Use 'Send to Interactive' (Alt-Enter or right-click) from an F# script. The F# Interactive process will
     use any global.json settings associated with that script.
  2. Press 'Enter' to start. The F# Interactive process will use default settings.
> 

Microsoft (R) F# Interactive version 12.5.0.0 for F# 7.0
Copyright (c) Microsoft Corporation. All Rights Reserved.

For help type #help;;

> val it: unit = ()

> val hasBreachedTarget: target: 'a -> total: 'a -> bool when 'a: comparison
val report: hasBreached: ('a -> bool) -> total: 'a -> Result<'a,'a>
 list -> Result<int,int>

>

However, if I reset the session, press Enter in the FSI window (do I have to do that, and if so, why?), and then execute the code in the same way I get:

Welcome to F# Interactive for .NET Core in Visual Studio. To execute code, either
  1. Use 'Send to Interactive' (Alt-Enter or right-click) from an F# script. The F# Interactive process will
     use any global.json settings associated with that script.
  2. Press 'Enter' to start. The F# Interactive process will use default settings.
> 
Microsoft (R) F# Interactive version 12.5.0.0 for F# 7.0
Copyright (c) Microsoft Corporation. All Rights Reserved.

For help type #help;;

> val it: unit = ()

> 
val hasBreachedTarget: target: 'a -> total: 'a -> bool when 'a: comparison
val report: hasBreached: ('a -> bool) -> total: 'a -> Result<'a,'a>
-> collection: int list -> Result<int,int>

>

I don’t know where the val it: unit = () comes from (in either run), or why the type signature for the report function is different between runs – list versus collection.

I’ve also had times where putting a newline at the end of the source code gives a slightly different result than not putting a newline at the end.

I’ve also had times where the FSI seems to have ‘forgotten’ some values/functions that I haven’t changed in the source code and I’ve had to execute the whole thing again to ‘re-educate’ it.

I really like the FSI but it can be frustrating sometimes when I don’t know if I can trust the output and have to run the same thing more than once, but maybe slightly differently, just in case it didn’t give me ‘the truth’ the first time.

TBH, I don’t use the “integrated” FSI because I don’t really get it. I just use my terminal window and manually launch dotnet fsi, and then I’ve remapped <Alt>+<Enter> to send the highlighted code to my terminal. What I don’t like is when I do that I don’t get the nice window that shows you the values of all your current variables, but I really value just being able to understand everything. I guess what I’m saying is it sounds to me like your issues are with the integrated FSI, and I don’t think I’m the right person to help with that :frowning: .

Thanks for the extra information.

I’ve just run the code via VS Code and I got the result I was originally expecting.

I guess it’s time for me to have a look at my development environment and see if I can get something better.