Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
Q#'s type inference algorithm is based on inference algorithms designed for the Hindley-Milner type system. While top-level callables must be declared with explicit type annotations, most types used within a callable can be inferred. For example, given these callables:
function Length<'a>(xs : 'a[]) : Int
function Mapped<'a, 'b>(f : 'a -> 'b, xs : 'a[]) : 'b[]
and this expression:
Mapped(Length, [[], ["a"], ["b", "c"]])
then the type argument to Length
is inferred as Length<String[]>
, and the type arguments to Mapped
are inferred as Mapped<String[], Int>
.
It isn't required to write these types explicitly.
Ambiguous types
Sometimes there isn't a single principal type that can be inferred for a type variable. In these cases, type inference fails with an error referring to an ambiguous type. For example, change the previous example slightly:
Mapped(Length, [[]])
What is the type of [[]]
?
In some type systems, it's possible to give it the type ∀a. a[][]
, but this isn't supported in Q#.
A concrete type is required, but there are an infinite number of types that work: String[][]
, (Int, Int)[][]
, Double[][][]
, and so on.
You must explicitly say which type you meant.
There are multiple ways to do this, depending on the situation. For example:
Call
Length
with a type argument.Mapped(Length<String>, [[]])
Call
Mapped
with its first type argument. (The_
for its second type argument means that it should still be inferred.)Mapped<String[], _>(Length, [[]])
Replace the empty array literal with an explicitly-typed call to a library function.
Mapped<String[], _>(Length, [EmptyArray<String>()])