I'm new to F# (and enjoying it so far), and I've been experimenting with code. I found something that I understand the cause of but not how to overcome it.
I have some code similar to the following:
let pairTest list = if List.length list = 2 then Some list else None
// This seems to compile and work just fine
[ [1; 2] ]
|> List.choose pairTest
|> List.map (fun l -> l |> List.map (fun i -> "a"))
|> List.choose pairTest
|> printfn "%A"
let testFunc groupTest =
[ [1; 2] ]
|> List.choose groupTest // Okay
|> List.map (fun l -> l |> List.map (fun i -> "a"))
|> List.choose groupTest // Error: expected int list, not string list
|> printfn "%A"
testFunc pairTest
I understand how F#'s type inference works, and I can see that in testFunc it's hitting int list on the first call to groupTest and then assigning that type (and examining the groupTest paramter in an IDE shows the type as int list -> int list option), which then makes it invalid for its second invocation. However, if I run the code outside of a function (the first function block), it works just fine and seamlessly switches pairTest<'a> between int list and string list.
My question is this: Is there a way to keep F# from locking down the type of groupTest? Or, if not, is there an (F#-idiomatic) way to approach this?
In this specific instance, I can just pass in a length parameter and move the List.length check inside the function, but I'm still curious about the answer for the more general case (if, say, my check were more complex, for instance.)