Ваша цель call(T, TT, A, _)
пытается вызвать nat
с тремя аргументами, но предиката nat/3
нет. У вас есть чеки на тип, но они приходят слишком поздно: ваш arity
чек должен прийти до соответствующего call
. Однако, даже тогда, во второй ветви вы проверяете тип T
с арностью 1, который будет list
, но нет никакого способа вызвать list/2
с тремя аргументами либо ...
Вся ваша модель несколько сбита с толку, потому что вы пытаетесь смоделировать все - и значения, и типы - в соответствии с предикатами Пролога. На самом деле ни один из них не должен быть предикатом. Даже не типы! может показаться хорошей идеей иметь типы в качестве предикатов, так как это будет разрешать такие запросы, как:
?- list(T, cons(0, nil)).
T = nat.
Но не было бы способа спросить "что это за тип cons(0, nil)
? ", Это, вероятно, тот тип вопросов, который вы хотели бы задать.
Поэтому вместо этого давайте смоделируем оба значения и их типы как термины, которые связаны отношением типизации, реализованным как Prolog сказуемое. Это очень просто:
value_type(Nat, nat) :-
nat(Nat).
value_type(nil, list(_A)).
value_type(cons(Head, Tail), list(A)) :-
value_type(Head, A),
value_type(Tail, list(A)).
nat(0).
nat(s(A)) :-
nat(A).
Итак, теперь мы можем задать вопрос сверху: «что это за список` cons (0, nil)? »:
?- value_type(cons(0, nil), list(T)).
T = nat.
Но также теперь мы можем спросить, «какой тип cons(0, nil)
?»:
?- value_type(cons(0, nil), T).
T = list(nat).
Это также легко распространить на другие виды значений. Каждый конструктор значений обычно должен добавлять одно определение к определению. Например, мы можем добавить сложение к натуральным числам и функцию length
, которая связывает мир списков с миром натуральных чисел:
value_type(X + Y, nat) :-
value_type(X, nat),
value_type(Y, nat).
value_type(length(Xs), nat) :-
value_type(Xs, list(_A)).
Позволяет нам печатать выражения вроде:
?- value_type(length(cons(nil, nil)) + length(nil), Type).
Type = nat.