Поделиться через


Автоматическое обобщение (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#)

Универсальные шаблоны (F#)

Статически разрешаемые параметры типа (F#)

Ограничения (F#)

Журнал изменений

Дата

Журнал

Причина

Май 2010

Исправлен код в случае 2.

Исправление ошибки содержимого.