AI Programming  (in C)
    
    Aim of this lecture,
    introduce
    list data structure, use of list to represent object in AI,
    programming
    with recursion to manipulate list.
    List
    A list is a collection of elements.  An element can be an atom
    or
    another list.  An atom is either "name" or "number" (other kind
    of
    atom will be introduced later).  A "name" is a string.  A
    number is an integer. A list can be printed on a screen using
    parentheses.  This is an example of a list containing two
    names:
    "A" and "B":
    
    (
        "A" "B" )   
    
    
    Here is many examples of  list:
    
    (1
        2 3 4)  
      ( (1 2) (3 4))
      ( ("A" 10) ("B" 20) ("C"
        30))
    
    
    The basic building block of list is a two-cell integer (called
    "cell").  The first cell is called "head".  The second
    cell
    is called "tail".  An atom has its head storing the type: name
    or
    number, and its tail storing the value.  For a name, the value
    is
    an index into a string-table.  For an integer, the value is the
    integer.  A structure of a list consisted of single linked
    list,
    using two-cell (called "dot-pair" as oppossed to "atom").  The
    head cell stores an index to an element (can be either an atom or
    another list).  The tail cell stores an index to the next
    cell.  At the end of list, the tail contains a NIL value.
    
    
    <picture of data structure of list>
    
    API (application program interface)
    The library (ailib.c)  contains many functions to create and
    manipulate list.  
    
    name(string)       creates an atom
    "string"
    number(n)         
    creates
    an atom n
    list(x)                
creates
    a list from an element x
    cons(a,b)          
creates
    a list with its head a, its tail b
    head(x)              the head of
    x,
    the first element of a list x
    tail(x)                 the
    tail of x, the list x without the first element
    print_list(x)        print the
    list
    x to show it on the screen
    isatom(x)          
return
    true if x is an atom
    islist(x)              
return
    true if x is a list
    
    There is an invariant showing the relationship between head, tail
    and
    cons:
    
         cons(head(x),
tail(x)) 
      ==  x
    
    cons(number(1),
      cons(number(2),
      cons(number(3), cons(number(4), NIL))))   == (1 2 3 4)
    cons(cons(number(1),
      cons(number(2), NIL)), 
          cons( cons(number(3), cons(number(4), NIL)),
      NIL))     == ((1 2 ) (3 4 ))
    cons( cons(name("A"),
      cons(number(10),NIL)) , 
        cons(
      cons(name("B"), cons(number(20), NIL)), 
        cons(
      cons(name("C"), cons(number(30),NIL)), NIL)))   
      ==  ( ("A" 10) ("B" 20) ("C" 30))
    
    Examples
    Here is an example how to create a list and show it:
    
    #include
        "ailib.h"
      
      int make_list(void){
         return
        cons(number(1), cons(number(2), cons(number(3), cons(number(4),
        NIL))));
      }
      
      int main(void){
        print_list(
        make_list() );
      }
    
    
    Set up your C compiler IDE environment, including "ailib.c" and
    "ailib.h" at the same directory as the application program.
    Now, we will make a simple program to count the number of elements
    of a
    simple list.
    
    int
        len(int ls){
        if(ls == NIL) return
        0;
        else return 1 +
        len(tail(ls));
      }
      
      int test_len(void){
        int a;
        a = make_list();
        printf("%d\n",
        len(a));
      }
    
    
     The "len" function works like this:  using a case
    analysis,
    if the list is empty (NIL) the number of element is 0, otherwise it
    is
    one pluses the length of the rest of the list (tail(ls)).
    
    Now we extend the "len" to cope with a complex list (its element can
    be
    another list).
    
    int
        len2(int ls){
        if(ls == NIL) return
        0;
        if(isatom(ls)) return
        1;
        else return
        len2(head(ls))
        + len2(tail(ls));
      }
      
      int make_complex_list(void){
        int a, b;
        a =
        cons(number(1),cons(number(2),NIL));
        b =
        cons(number(3),cons(number(4),NIL));
        return cons(a,
        cons(b,
        NIL));
      }
      
      void test_len_complex(void){
        int a;
        a =
        make_complex_list();
        printf("%d\n",
        len(a));
        printf("%d\n",
        len2(a));
      }
    
    
    If we apply "len" to a complex list, it will count the element, if
    an
    element is a list, it counts as one.  "len" does not get "into"
    the element when it is a list.  "len2" checks if an element is
    a
    list, it is recursively walking into that list and count its
    element.
       
     
    The "len" function shows us how to traverse the list structure
    recursively.  Next, we learn how to "create" a duplicate of a
    list
    (using "cons").  It is quite similar to "len".  Start with
    a
    simple list.  We introduce a new function:
    
    clone_atom(x)      creates a duplicate of
    an
    atom x
    
    int
        copy_list(int ls){
        if(ls == NIL) return
        NIL;
        else return
        cons(clone_atom(head(ls)), copy_list(tail(ls)));
      }
      
      void test_copy(void){
        int a, b;
        a = make_list();
        b = copy_list(a);
        print_list(a);
      }
    
    
    We can extend "copy_list" to cope with a complex list, not much
    different from "len2".
    
    int
        copy_list_complex(void){
        if(ls == NIL) return
        NIL;
        if(isatom(ls)) return
        clone_atom(ls);
        else return cons(
        copy_list_complex, copy_list_complex(tail(ls)));
      }
      
      void
        test_copy_complex(void){
        int a, b;
        a =
        make_list_complex();
        b = copy_list2(a);
        print_list(b);
      }
    
    
    If the list is empty "copy_list_complex" terminates by returning a
    NIL.  If input is an atom, return a duplicate of that
    atom. 
    Otherwise the list is complex, walk into the first element and make
    a
    duplicate (recursively), and do the rest of the list, then "cons"
    them
    together. The "copy_list_complex" can copy a list with an arbitrary
    length and shape!
    
    Some excercises
    1)   Write a program to increment one of all elements of a
    simple list of integers.  (1
      2 3 4)  => (2 3 4 5)
    2)   Write a program to reverse a simple list.  (1 2 3 4) => (4 3 2 1)
    3)    Write a program to divide a simple list into a list
    with two elements, each is a list containing half of element of the
    original.  (assuming the length of the input list is a even
    number)
    4)    Write a search function of an "associative
    list". 
    An associative list contains a list of records, a record is a pair
    of:
    the first element is a "key" which is a a name, the second element
    is
    the value, an integer.  Given a key, find the value associate
    with
    that key.  Here is an example:  
    a
        = cons(name("mango"), cons(number(3), NIL));
      b = cons(name("orange"),
        cons(number(5), NIL));
      table = cons(a, cons(b,
        NIL));
    
        
    a table is  ( ( "mango"
      3 )
      ("orange" 5) )
    
    search(table,
        name("orange"))  =>   5
      search(table, name("ice
        cream"))
        => NIL
    
    
    This is different from an ordinary array which index must be
    integer.
    
    Enjoy!
    
    last update 17 Oct 2011