Я пытался сделать хвостовую рекурсивную версию этой очень простой функции SML:
fun suffixes [] = [[]]
| suffixes (x::xs) = (x::xs) :: suffixes xs;
В течение этого времени я использовал аннотации типов для параметров. Следующий код показывает это и вызывает ошибку типа (приведенную ниже), тогда как, если я просто удаляю аннотации типов, SML принимает это без проблем, давая всей функции ту же сигнатуру, что и у простой функции, описанной выше.
fun suffixes_tail xs =
let
fun suffixes_helper [] acc = []::acc
| suffixes_helper (x::xs:'a list) (acc:'b list) =
suffixes_helper xs ((x::xs)::acc)
in
suffixes_helper xs []
end;
Ошибка:
$ sml typeerror.sml
Standard ML of New Jersey v110.71 [built: Thu Sep 17 16:48:42 2009]
[opening typeerror.sml]
val suffixes = fn : 'a list -> 'a list list
typeerror.sml:17.81-17.93 Error: operator and operand don't agree [UBOUND match]
operator domain: 'a list * 'a list list
operand: 'a list * 'b list
in expression:
(x :: xs) :: acc
typeerror.sml:16.13-17.94 Error: types of rules don't agree [UBOUND match]
earlier rule(s): 'a list * 'Z list list -> 'Z list list
this rule: 'a list * 'b list -> 'Y
in rule:
(x :: xs : 'a list,acc : 'b list) =>
(suffixes_helper xs) ((x :: xs) :: acc)
/usr/local/smlnj-110.71/bin/sml: Fatal error -- Uncaught exception Error with 0
raised at ../compiler/TopLevel/interact/evalloop.sml:66.19-66.27
Даны две ошибки. Последнее кажется здесь менее важным, несоответствие между двумя пунктами суффикса_helper. Первый - тот, который я не понимаю. Я отмечаю, что первый параметр имеет тип 'a:list
, а второй - тип 'b:list
. Не должен ли алгоритм логического вывода типа Хиндли-Милнера, построенный на вершине общего объединения, насколько я понимаю, быть в состоянии объединить 'b:list
с 'a:list list
, используя подстановку 'b ---> 'a list
?
РЕДАКТИРОВАТЬ: Ответ предполагает, что он может иметь какое-то отношение к алгоритму вывода типов, запрещающему выведенные типы, которые в некотором смысле более строгие, чем те, которые даются аннотациями типов. Я предполагаю, что такое правило будет применяться только к аннотациям на параметры и на функцию в целом. Я понятия не имею, если это правильно. В любом случае я пытался переместить аннотации типов в тело функции, и я получаю такую же ошибку:
fun suffixes_helper [] acc = []::acc
| suffixes_helper (x::xs) acc =
suffixes_helper (xs:'a list) (((x::xs)::acc):'b list);
Ошибка теперь:
typeerror.sml:5.67-5.89 Error: expression doesn't match constraint [UBOUND match]
expression: 'a list list
constraint: 'b list
in expression:
(x :: xs) :: acc: 'b list