2015-05-20 7 views
1

Я пытаюсь рассчитать общее время, которое я трачу на поездку, учитывая час вылета и прибытия всех мест.Prolog - Рассчитать общее время поездки

Я пытаюсь использовать эту функцию только для расчета времени я буду ждать следующего транспорта:

time_out([(_,Hf1),(Hi2,Hf2)|R],To):- 
    diff_t(Hi2,Hf1,To_I), 
    time_out([(Hi2,Hf2)|R],To_R), 
    To is To_R + To_I. 

diff_t(Hi,Hf,D):-Hf>Hi, D is Hf - Hi. 
diff_t(Hi,Hf,D):-Hf=<Hi,HCA is Hf + 2400, D is HCA - Hi. 

Когда я тестирую его:

?- time_out([(_,1300),(1400,1600)],T). 
false. 

Почему Безразлично «Это дает мне общее время, которое я хочу?

+0

Пожалуйста, поясните, правильный ответ на примере вы предоставляете это? –

ответ

1

Как Пауло уже сказал, вам необходимо базовое условие для рекурсии:

time_out([_], 0). 
time_out([(_, Hf1), (Hi2, Hf2)|R], To) :- 
       diff_t(Hi2, Hf1, To_I), 
       time_out([(Hi2, Hf2)|R], To_R), 
       To is To_R + To_I. 
+0

Это решение неверно, потому что я объясняю в своем ответе: когда вы вызываете предикат с непустым списком, вы в конечном итоге попытаетесь доказать цель со списком с ** отдельным ** элементом. Эта цель потерпит неудачу, что приведет к провалу исходной цели, так как ни одно из этих двух положений не применяется. –

+0

о, да, хорошо поймать. исправлено. –

1

Предикат time_out/2 имеет только одну, рекурсивную, оговорку. Где базовое предложение? Этот рекурсивный пункт пересекает список. Предполагая, что предикат вызывается с закрытым списком, вы в конечном итоге будете вызывать предикат с пустым списком в качестве первого аргумента. Поскольку нет предложения с объединением головы с этой целью, вызов терпит неудачу.

Также обратите внимание, что ваше предложение не является хвостовым рекурсивным. То есть в этом случае есть цель после вызова рекурсивного вызова. Это означает, что эта цель должна быть сохранена в стеке (для каждого рекурсивного вызова) до тех пор, пока не будет найден базовый случай. Это пространство для отходов (линейное и число рекурсивных вызовов). Решение для преобразования вашего предиката в хвостовой рекурсивный предикат в этом случае (и в целом) используется для использования аккумулятора на расстоянии, которое вы вычисляете. Когда вы достигнете (отсутствующий базовый вариант), значение аккумулятора будет расстояние вы вычисления:

time_out(Stops, Distance) :- 
    % the initial value of the accumulator is zero 
    % as we're computing the sum of distances 
    time_out(Stops, 0, Distance). 

time_out([], Distance, Distance). 
time_out([(_, End1), (Start2, End2)| Stops], Distance0, Distance) :- 
    diff_t(Start2, End1, Leg), 
    Distance1 is Leg + Distance0, 
    time_out([(Start2, End2)| Stops], Distance1, Distance). 

Но это определение не является правильным. Вы можете определить проблему? Что происходит, когда в списке содержится одна пара стартового конца? Вы можете исправить это определение? Возможно, у нас есть неправильный базовый чехол?

Большинство систем Пролог обеспечивают след особенность, которая часто помогает в понимании Пролога вычислений:

?- trace. 
true. 

[trace] ?- time_out([(_,1300),(1400,1600)],T). 
    Call: (7) time_out([ (_G2156, 1300), (1400, 1600)], _G2169) ? creep 
    Call: (8) time_out([ (_G2156, 1300), (1400, 1600)], 0, _G2169) ? creep 
    Call: (9) diff_t(1400, 1300, _G2261) ? creep 
    Call: (10) 1300>1400 ? creep 
    Fail: (10) 1300>1400 ? creep 
    Redo: (9) diff_t(1400, 1300, _G2261) ? creep 
    Call: (10) 1300=<1400 ? creep 
    Exit: (10) 1300=<1400 ? creep 
    Call: (10) _G2262 is 1300+2400 ? creep 
    Exit: (10) 3700 is 1300+2400 ? creep 
    Call: (10) _G2265 is 3700-1400 ? creep 
    Exit: (10) 2300 is 3700-1400 ? creep 
    Exit: (9) diff_t(1400, 1300, 2300) ? creep 
    Call: (9) _G2268 is 2300+0 ? creep 
    Exit: (9) 2300 is 2300+0 ? creep 
    Call: (9) time_out([ (1400, 1600)], 2300, _G2169) ? creep 
    Fail: (9) time_out([ (1400, 1600)], 2300, _G2169) ? creep 
    Fail: (8) time_out([ (_G2156, 1300), (1400, 1600)], 0, _G2169) ? creep 
    Fail: (7) time_out([ (_G2156, 1300), (1400, 1600)], _G2169) ? creep 
false. 

Посмотрите внимательно на вызов (9). Я дам вам до завтра, чтобы вы нашли решение этой ошибки. Счастливый взлом!

UPDATE

Теперь, когда ОП нашел рабочий раствор время, чтобы исправить это. Например, написав:

time_out([(_, End1)| Stops], Distance) :- 
    % the initial value of the accumulator is zero 
    % as we're computing the sum of distances 
    time_out(Stops, End1, 0, Distance). 

time_out([], _, Distance, Distance). 
time_out([(Start2, End2)| Stops], End1, Distance0, Distance) :- 
    diff_t(Start2, End1, Leg), 
    Distance1 is Leg + Distance0, 
    time_out(Stops, End2, Distance1, Distance). 

Следует отметить, что большинство систем Пролога осуществить оптимизацию, называемой первого аргумент индексацией, что позволяет пробуя положения, которые могут быть в состоянии решить текущую задачу. Эта оптимизация обычно реализуется, рассматривая тип и, в атомных терминах, в некоторых случаях значение первого аргумента (если оно связано). Первый аргумент в двух положений для time_out/4 предиката, для первой, атом[] (пустой список не список), а для второго список с одним или несколькими элементами. Таким образом, принимая эту оптимизацию, правильное предложение будет выбираться каждый раз при вызове этого предиката (с, конечно, с его первым аргументом, созданным экземпляром), тем самым избегая ложных точек выбора.Тем не менее, такая же оптимизация не применяется в случае вашего решения, так как в обоих предложениях для вашего предиката time_out/2 первым аргументом является список.

+1

Я решил это добавить: time_out ([_], 0). – sirsomething

+0

Это прогресс, и он работает. Предлагаю вам изменить свой вопрос с помощью найденного решения. Но есть проблема с этим решением: он оставляет ложную точку выбора ... –

+0

Я думаю, что путаница возникает из смешения концепции списка как структуры данных ** ** с ее ** представлением ** с использованием двух разных ** Типы терминов Prolog **: атом для пустого списка - составной термин для непустых списков. Но это существенно не отличается от, скажем, списка на C, где список заканчивается константой 'NULL'. В Prolog атом '[]' играет ту же роль, что и константа 'NULL' в C. Я также ожидал бы, что большинство пользователей SO смогут перенести свои знания списков с других языков программирования при обучении Prolog. –

Смежные вопросы