Why does removing the (:int) from a parameter definition in this function cause an error?

Upfront admission: I know that this code is horrible and doesn’t work well. I’m using different code now but am still curious as to why the problem occurred.

I have had to put (:int) around the maximum parameter in this function as otherwise maximum gets typed as unit and the last line of the function shows an “FS0193 The type ‘int’ does not match the type ‘unit’” error on minimum.

let greyscaleGradient minimum (maximum:int) numberOfItems : int seq =
 if numberOfItems > 1 then
 let step = (maximum - minimum) / (numberOfItems - 1)
 let calculatedValues = seq {for n in 0..(numberOfItems-2) -> n * step}
 Seq.append calculatedValues (seq {maximum})
 else
 seq {minimum}
greyscaleGradient 0 255 5 |> Seq.toList

Why would this be?
I’m clearly doing some calculations with maximum so why does the compiler think maximum should be unit?

Well, I’ll take a stab at answering this, though I’m not very clear on the answer myself. It seems to definitely be related to the syntax for seq {maximum}. As far as I know, I don’t think that syntax was always allowed. I believe you used to have to say seq { yield maximum }, and in fact, if I add the word yield to your example, then the annotation isn’t needed anymore. Alternatively, if you return a list: [maximum] instead of a seq, then it’s fine too. I think this is because it’s allowable to have an expression evaluate to unit inside a seq expression, such as

seq { 
  printfn "hello" // <-- evaluates to `unit`
  yield 5 // <-- evaluates to an int
}

In fact, this is even valid F#

let xs : int seq = seq { printfn "hello" }

where xs evaluates to an empty seq, and prints “hello” in the process of evaluating. If I try the same thing with a list, it doesn’t work.

My guess is when they loosened the syntax for seq expressions to allow for something like seq { maximum }, there’s still an open edge case with the type inference engine. It still surprises me, because I would think the (maximum - minimum) part would tell the compiler what it needs.

Thanks for the explanation.
I don’t understand it fully, yet, but at least I know that it’s something I’m doing wrong rather than something else.

I simplified the code to this:

let oneOrTwo first second bothValues =
 if bothValues then
 let calculatedValues = seq { yield first }
 Seq.append calculatedValues (seq { yield second })
 else
 seq { yield first }
oneOrTwo 0 255 true |> Seq.toList

…and removing the yields makes both first and second to be inferred as unit and I get the same error as before.

I still have lots of things to learn about sequences so a better understanding may come to me later; at least I know that I shouldn’t be doing it the way I was doing it.
Thanks again.