Автоматическое обобщение (F#)
В языке F# для оценки типов функций и выражений используется вывод типа. В данном разделе описывается, как в языке F# автоматически обобщаются аргументы и типы функций, чтобы они работали с несколькими типами, когда это возможно.
Автоматическое обобщение
Когда компилятор F# выполняет вывод типа для функции, он определяет, может ли заданный параметр быть универсальным. Компилятор проверяет каждый параметр и определяет, зависит ли функция от конкретного типа этого параметра. Если такой зависимости нет, делается вывод, что тип является универсальным.
В следующем примере кода показывается функция, в отношении которой компилятор делает вывод, что она является универсальной.
let max a b = if a > b then a else b
Делается следующий вывод о типе: 'a -> 'a -> 'a.
Тип указывает, что функция принимает два аргумента одного и того же неизвестного типа и возвращает значение такого же типа. Одна из причин, по которой указанная выше функция может быть универсальной, состоит в том, что оператор "больше чем" (>) сам является универсальным. Оператор "больше чем" имеет сигнатуру 'a -> 'a -> bool. Не все операторы являются универсальными, и если код в функции использует тот или иной тип параметра вместе с неуниверсальной функцией или оператором, такой тип параметра обобщить нельзя.
Поскольку функция max является универсальной, ее можно использовать с типами int, float и т. д., как показано в следующих примерах.
let biggestFloat = max 2.0 3.0
let biggestInt = max 2 3
Однако два аргумента должны быть одного типа. Сигнатура — 'a -> 'a -> 'a, а не 'a -> 'b -> 'a. Поэтому следующий код выдает ошибку, поскольку типы являются несоответствующими.
// Error: type mismatch.
let biggestIntFloat = max 2.0 3
Функция max также работает с любым типом, который поддерживает оператор "больше чем". Следовательно, ее можно также использовать для строки, как показано в следующем коде.
let testString = max "cab" "cat"
Ограничение значений
Компилятор выполняет автоматическое обобщение только для полных определений функций, которые содержат явно заданные аргументы, и для простых постоянных значений.
Это означает, что при попытке выполнить компиляцию кода, который в достаточной степени не ограничен конкретным типом, но также не является обобщаемым, компилятор выдает ошибку. В сообщении об ошибке по данной проблеме делается ссылка на это ограничение по автоматическому обобщению для значений в виде ограничение значений.
Обычно ошибка, связанная с ограничением значений, происходит либо тогда, когда требуется, чтобы конструкция была универсальной, но компилятор имеет недостаточно информации для ее обобщения, либо тогда, когда достаточные сведения о типе в неуниверсальной конструкции непреднамеренно опускаются. Чтобы решить проблему ошибки ограничения значений, следует предоставить больше явно заданных сведений для более полного устранения проблемы вывода типа одним из следующих способов.
Сделайте тип неуниверсальным, добавив к значению или параметру явно определенную заметку в отношении типа.
Если проблема заключается в применении для определения универсальной функции необобщаемой конструкции, например, объединения функций или неполностью примененных аргументов каррированной функции, попробуйте переписать эту функцию, используя обычное определение функции.
Если проблема заключается в выражении, которое является слишком сложным для обобщения, преобразуйте его в функцию, добавив дополнительный неиспользуемый параметр.
Добавьте явно заданные параметры универсального типа. Этот параметр используется редко.
В следующих примерах кодов представлен каждый из указанных выше сценариев.
Случай 1: слишком сложное выражение. В этом примере список counter должен представлять собой int option ref, но он не определен как простое неизменное значение.
let counter = ref None
// Adding a type annotation fixes the problem:
let counter : int option ref = ref None
Случай 2: использование необобщаемой конструкции для задания универсальной функции. В этом примере конструкция является необобщаемой, так как в ней используется частичное применение аргументов функции.
let maxhash = max hash
// The following is acceptable because the argument for maxhash is explicit:
let maxhash obj = max (hash obj)
Случай 3: добавление дополнительного неиспользуемого параметра. Так как это выражение слишком сложно для обобщения, компилятор выдает ошибку ограничения значения.
let emptyList10 = Array.create 10 []
// Adding an extra (unused) parameter makes it a function, which is generalizable.
let emptyList10 () = Array.create 10 []
Случай 4: добавление параметров типа.
let emptyset = Set.empty
// Adding a type parameter and type annotation lets you write a generic value.
let emptyset<'a> : Set<'a> = Set.empty
См. также
Ссылки
Статически разрешаемые параметры типа (F#)
Журнал изменений
Дата |
Журнал |
Причина |
---|---|---|
Май 2010 |
Исправлен код в случае 2. |
Исправление ошибки содержимого. |