'"let is unfinished. expect an expression" error. I don't see where though

open System

let highLowGame () = 
    let rng = new Random();
    let secretNumber = rng.Next() % 100 + 1

    let rec highLowGameStep () = 
        printfn "Guess a number: "
        let guessStr = Console.ReadLine()
        let guess = Int32.Parse(guessStr)
        match guess with
        | _ when guess > secretNumber -> printfn "Too high!" highLowGameStep ()
        | _ when guess = secretNumber -> printfn "You got it!" ()
        | _ when guess < secretNumber -> printfn "Too low!" highLowGameStep ()


[<EntryPoint>]
let main argv = 
    highLowGame ()
    0 // return an integer exit code

I know there's tons of these questions and I get that a function in F# must have a return variable. Mine is here | _ when guess = secretNumber -> printfn "You got it!" () so I don't understand why it keeps telling me that my block is unfinished

This example is straight out of the F# 3.0 book.

/stdin(14,13): error FS0010: Unexpected identifier in expression. Expected incomplete structured construct at or before this point or other token.

is the full error.

f#


Solution 1:[1]

You have to return something at the end of your let statement. Otherwise, your function just defines some values, but the expression isn't complete - you're missing a return value. See this MSDN link for more details.

In this case, you can add highLowGameStep () at the end to call the function and get its return value:

open System

let highLowGame () = 
    let rng = new Random();
    let secretNumber = rng.Next() % 100 + 1

    let rec highLowGameStep () = 
        printfn "Guess a number: "
        let guessStr = Console.ReadLine()
        let guess = Int32.Parse(guessStr)
        match guess with
        | _ when guess > secretNumber -> printfn "Too high!" highLowGameStep ()
        | _ when guess = secretNumber -> printfn "You got it!" ()
        | _ when guess < secretNumber -> printfn "Too low!" highLowGameStep ()

    highLowGameStep ()


[<EntryPoint>]
let main argv = 
    highLowGame ()
    0 // return an integer exit code

Solution 2:[2]

I was getting the same error as OP for a different reason. The reason was improper indentation. Here is my code:

open System

 type Temperature = F of int | C of int
    
[<EntryPoint>]
let main (argv : string[]) = 
     let freezing = F 32;
  Console.WriteLine("A union: {0}", freezing ); //problematic indentation
  printfn "A union: %A" freezing ; //problematic indentation
     0

I had copy pasted two lines of code (marked as problematic indentation in comments) from a website and it went haywire. It was giving me three different compile time errors at three different lines of code within main function. When I aligned the indentation of all four statements within main function the issue got resolved:

let main (argv : string[]) = 
     let freezing = F 32;
     Console.WriteLine("A union: {0}", freezing );
     printfn "A union: %A" freezing ;
     0

I would encourage you to enable View White Space option in Visual Studio IDE while working on F# as mentioned here. Tabs, spaces and code indentation is strongly connected to scoping in F#. Read these posts to gather more understanding around scoping and indentation in F#:

Solution 3:[3]

Roujo has an excellent answer to your question, I'm throwing up another answer to go more in depth into the fundamentals of what's going on.

The key to remember is that everything in F# must be an expression and an expression is something which has a value. That value could be an integer or a float or a function, but it's gotta have a value. The let isn't, on it's own, an expression; it's a binding of a value to a name so that name can be used in an expression. In your code, you've bound the name highLowGameStep to a function value, but you don't use that name in an expression. The F# compiler is basically left holding the bag, wondering what expression highLowGameStep should be used in.

It helps to use the verbose F# syntax to see what's happening. In verbose F# the code for your function is (note the in keyword after each let binding):

let rng = new Random() in
let secretNumber = rng.Next() % 100 + 1 in

let rec highLowGameStep () = 
    printfn "Guess a number: "
    let guessStr = Console.ReadLine()
    let guess = Int32.Parse(guessStr)
    match guess with
    | _ when guess > secretNumber -> 
        printfn "Too high!"
        highLowGameStep ()
    | _ when guess = secretNumber ->
        printfn "You got it!"
    | _ when guess < secretNumber -> 
        printfn "Too low!"
        highLowGameStep ()
in

In this syntax, it's obvious what's wrong: there's nothing after the last in where F# expects an expression. (Incidentally, the code in the match statements wouldn't have executed because there needed to be a line or ; separating the printfn function call and the call to highLowGameStep.)

Quick summary, the let is binding a name to a value to be used in an expression. In the code example, there was no expression for the bound name to be used in and the compiler failed.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Roujo
Solution 2
Solution 3 egerhard