Основная проблема в том, что ваша функция runProgram
является полиморфной второго ранга, или, другими словами, использование полиморфной функции в качестве аргумента немного сложнее.
Более серьезно, в синтаксисе фэнтези, тип runProgram
будет ('a. 'a => 'a)=> unit
, где 'a. 'a => 'a
обозначает функцию, которая требуется для работы с любым 'a
.Это отличается от функции, подобной
let apply: 'a. ('a -> 'a) -> 'a -> 'a = (f, x) => f(x)
, где сначала вводится переменная типа 'a
(в позиции prenex), а затем аргумент функции требуется для работы только с этим конкретным типом 'a
.Например,
let two = apply( (x)=> 1 + x, 1)
действителен, даже если (x)=> 1 + x
работает только для целых чисел.Принимая во внимание, что
let fail = runProgram((x) => 1 + x)
терпит неудачу, потому что (x) => 1 + x
не может работать со строками.
Возвращаясь к проблеме вывода типов, причина, по которой средство проверки типов не может вывести тип, который вы имели в виду, заключается в том, что вывод типов и полиморфизм более высокого ранга плохо сочетаются (точнее, вывод типов неразрешим вналичие полиморфизма высшего ранга).Чтобы понять почему, рассмотрим эту простую функцию
let ambiguous(f,x) = f(1)+f(x)
Тип, определяемый средством проверки типов для ambiguous
, равен (int=>int)=>int=>int
.Однако если я заменим f
на запись с полиморфным полем (что является одним из двух способов записи полиморфной функции высшего порядка в OCaml)
type const = {f:'a. 'a => int}
let ambiguous({f},x) = f(1)+f(x)
типа ambiguous
(всинтаксис фантазии) становится ('a.'a=>int)=>'a=>int
.Другими словами, если бы вывод типа мог вывести полиморфизм более высокого ранга, ему пришлось бы выбирать между ('a.'a=>int)=>'a=>int
и (int=>int)=>int=>int
.И между этими двумя типами нет явного победителя: первый тип имеет сильные ограничения на свой первый аргумент и более слабый на свой второй аргумент, а второй тип является совершенно противоположным.Это общая проблема с полиморфизмом более высокого ранга: существует много потенциальных вариантов выбора без очевидного наилучшего выбора.
Вот почему средство проверки типов должно быть достаточно явным при написании полиморфной функции высшего ранга:
type program = { program: 'a. 'a => 'a }
let runProgram = ({program}) => {
let _y1 = program(10);
let _y2 = program("Something");
}
См. Также руководство OCaml по http://caml.inria.fr/pub/docs/manual-ocaml/polymorphism.html#sec61.