рекурсия в прологе (по спискам) - PullRequest
4 голосов
/ 29 апреля 2011

Может кто-нибудь, пожалуйста, помогите мне просто с основами по выполнению рекурсивных функций пролога.

append([],X,X). % base
append([X|Y],Z,[X|W]) :- append(Y,Z,W). %recursive

% base case
addup([], 0). % sum of the empty list of numbers is zero

% recursive case: if the base-case rule does not match, this one must:
addup([FirstNumber | RestOfList], Total) :-
    addup(RestOfList, TotalOfRest),   % add up the numbers in RestOfList
    Total is FirstNumber + TotalOfRest.

Может кто-нибудь объяснить, как на английском, так и на C / C ++ / Java независимо от того, как ...Я на самом деле предпочел бы видеть что-то вроде добавления или реверса ... Я в основном просто манипулирую списками переменных вместо целых чисел ... (Я пытался проработать добавление как 10 раз ... тьфу).

Ответы [ 4 ]

5 голосов
/ 29 апреля 2011

append(A, B, R) означает, что R является результатом добавления A к B.

Базовый корпус

append([], X, X).

говорит, что если A = [] и B = X, то R = X = B: пустой список A, добавленный к другому списку B, равен B.

Рекурсивный случай

append([X | Y], Z, [X | W]) :- append(Y, Z, W).

говорит, что если A = [X | Y] - это непустой список для добавления к B = Z, а если W - это Y, добавляемый к Z, то R = [X | W].

Еще один способ сказать, что это так: добавить непустой список A в другой список B, сначала добавить хвост от A к B, а затем добавить голову A к перед списком.

3 голосов
/ 29 апреля 2011

В бесплатной онлайн-книге «Learn Prolog Now» есть раздел, посвященный объяснению шагов, которые выполняет добавление:

http://cs.union.edu/~striegnk/learn-prolog-now/html/node47.html#subsec.l6.defining.append

0 голосов
/ 29 апреля 2011

Рекурсия в прологе практически идентична рекурсии на любом другом языке. Хитрость с прологом в том, что

  • каждая переменная является локальной, и,
  • после объединения переменные перестают быть переменными. Они никогда не могут изменить значение.

Это означает, что вам часто нужно будет создавать то, что я буду называть «рабочими» предикатами, которые выполняют реальную работу и содержат около 1 или более переменных, которые действуют как рабочее хранилище. Вот реализация sum / 2 для суммирования списка целых чисел:

% sum/2
sum( [] , 0 ).
sum( [X|Xs] , Total) :-
  sum(Xs,X,Total).

% sum/3 (worker predicate)
sum( [], Total, Total ).
sum( [X|Xs] , Subtotal , Total ) :-
  NewSubTotal is Subtotal + X ,
  sum( Xs , NewSubTotal , Total ).

Вот реализация в ANSI C, которая близко отражает вышеприведенный код пролога:

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
// linked list structure
typedef struct listnode
{
  int              value ;
  struct listnode *next  ;
} LISTNODE ;

// core recursive worker function
int sum_core( int subtotal , LISTNODE *list )
{
  LISTNODE *head ;
  LISTNODE *tail ;
  int       list_item ;

  if ( list == NULL ) return subtotal ;

  head      = list        ;
  tail      = list->next  ;
  list_item = head->value ;

  return sum_core( subtotal + head->value , tail ) ;

}

// external interface
int sum( LISTNODE *list )
{
  LISTNODE *head      ;
  LISTNODE *tail      ;
  int       list_item ;

  if ( list == NULL ) return 0 ;

  head      = list        ;
  tail      = list->next  ;
  list_item = head->value ;

  return sum_core( list->value , tail ) ;

}

int main ( int argc , char * argv[] )
{
  LISTNODE *list ;
  int       total ;

  list                   = malloc(sizeof(LISTNODE)) ; list->value             = 1 ;
  list->next             = malloc(sizeof(LISTNODE)) ; list->next->value       = 2 ;
  list->next->next       = malloc(sizeof(LISTNODE)) ; list->next->next->value = 3 ;
  list->next->next->next = NULL ;

  total = sum( list ) ;

  return ;
}
0 голосов
/ 29 апреля 2011

Вы хотите увидеть это в C ++?

int const a[] = {1,2,3,4,5};
size_t const N = sizeof(a) / sizeof(int);

void addup(size_t depth, int &total)
{
    if (depth == N)   // base case; sum of no numbers is zero
        total = 0;
    else {            // recursive case
        int first_number = a[depth];
        size_t rest_of_list = depth+1;
        int total_rest;
        addup(rest_of_list, total_rest);
        total = first_number + total_rest;
    }
}

Я сразу признаю, что это ужасно безобразный C ++, но это прямой перевод программы Prolog, за исключением того, что списки моделируются с использованием массивов и счетчика глубины.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...