Можно ли иметь параметр, представляющий что-то вроде id
(что-то типа 'T -> 'T
), и использовать его в общем?
то есть ниже у меня есть id_like
, что я хотел бы иметь возможность работать с объектами любого типа. Однако оказывается, что как только я работаю с объектом определенного типа, компилятор специализируется id_like
и не позволяет ему работать ни с чем другим.
Ниже я получаю FS0064: This construct causes code to be less generic than indicated by the type annotations
, когда я работаю с a
, а затем ошибка компиляции, когда я пытаюсь работать с b
.
let f (id_like: 'T -> 'T) (a: int) (b: bool) =
let a1 = id_like a
let b1 = id_like b
a1, b1
let _ = f id 0 false
Если нет, то это просто артефакт использования Хиндли-Милнера? Является ли HM «жадным» в случаях, когда параметры содержат функции?
К сожалению, это не разрешено, потому что это сделало бы вывод типа неразрешимым. Полученный язык эквивалентен System F (полиморфное лямбда-исчисление).
Вместо этого системы типов Хиндли-Милнера обеспечивают «let-полиморфизм»: только значения, связанные в конструкции let
, являются полиморфными:
let id x = x
in ... (id 3) ... (id "text") ...
Параметры в лямбда-абстракциях (т. е. определениях функций) мономорфны.
F# использует дженерики .NET, поэтому я не думаю, что это возможно. Он также не поддерживается в C#.
Спасибо также за образование. Я работал время от времени (в основном без перерыва) в течение пары лет, пытаясь создать механизм вывода типов, который делал бы именно это, что и было реальной мотивацией вопроса. (И пытаясь сделать это, не ссылаясь ни на что, чтобы я мог видеть, что я могу придумать). Приятно осознавать, что у него уже есть имя, и это доказуемо неразрешимо, и я могу перейти к моему следующему проекту.
вы можете обойти проблему, обернув функцию в интерфейс
type Id_Wrapper() =
member __.Apply<'a> (x: 'a) = id x
let g (id_like : Id_Wrapper) (a: int) (b: bool) =
let a1 = id_like.Apply a
let b1 = id_like.Apply b
a1, b1
тип выводится для каждого приложения Apply, которые затем могут быть разными типами
этот код компилируется
Спасибо! Похоже, что «пусть полиморфизм» требуется только для вывода типа. Знаете ли вы, есть ли техническая причина, по которой это также невозможно, когда тип явно аннотирован? Или это то, что потенциально может быть добавлено в компилятор?