Основная проблема заключается в том, что ваша функция runProgram
является полиморфной второго ранга, или, другими словами, использование полиморфной функции в качестве аргумента немного сложно.
Более серьезно, в синтаксисе фэнтези тип runProgram
будет ('a. 'a => 'a)=> unit
, где 'a. 'a => 'a
обозначает функцию, которая требуется для работы для любого 'a
. Это контрастирует с такой функцией, как
let apply: 'a. ('a -> 'a) -> 'a -> 'a = (f, x) => f(x)
где переменная типа 'a
вводится первой (в предвешенной позиции), а затем требуется, чтобы аргумент функции работал только с этим конкретным типом '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.
person
octachron
schedule
06.02.2019