[Date Prev] [Date Next] [Thread Prev] [Thread Next] Date Index Thread Index Search archive:
Date:Mon Mar 10 21:08:37 1994 
Subject:Re: Another Pop-11 style question: nexstates 
From:Steve Knight 
Volume-ID:940310.05 

Aaron writes:
> For those who have never looked at it, teach tower introduces searching
> in Pop-11 via the problem of building a tower of a given total height
> from a set of blocks of varying heights. It's a nice simple problem to
> start with because it maps onto the problem given a set of numbers, e.g.
> [ 1 3 4 7 8 2 9] find a subset that adds up to a given target, e.g. 13.

Although this does not answer Aaron's subsequent question, I thought the
following technique for solving this problem might be of interest.  We first
write a couple of familiar routines:

    ;;; Given a procedure, return a dynamic list.  The procedure is expected
    ;;; to suspend in order to return its results.  This is just more convenient
    ;;; for writing power_list.
    ;;;
    define rptr_to_list( r ); lvars r;
        pdtolist( runproc(% 0, consproc( 0, r ) %) )
    enddefine;
    
    ;;; Given a list, return a list of all sublists of that list.  Note that
    ;;; this implementation preserves order of elements.  (At the expense of
    ;;; efficiency.)  It also works on dynamic lists(!).
    ;;;
    define power_list( L ); lvars L;
        lvars sofar = [];
    
        define lconstant solution( x ); lvars x;
            conspair( x, sofar ) -> sofar;
            chain( x.rev, 1, suspend )
        enddefine;
    
        procedure();
            solution( [] );
            lvars i, s;
            for i in L do
                for s in sofar do
                    solution( i :: s )
                endfor
            endfor;
            termin
        endprocedure.rptr_to_list
    enddefine;
    
    ;;; Given a list and a predicate, create a new list, elements of which
    ;;; are selected from the old list using the predicate.  It is important
    ;;; that this implementation works on dynamic lists.
    ;;;
    define select( L, pred ); lvars L, pred;
        procedure();
            until null( L ) do
                lvars it = L.dest -> L;
                if pred( it ) then
                    return( it )
                endif;
            enduntil;
            return( termin )
        endprocedure.pdtolist
    enddefine;
    
    ;;; Given a list of numbers, compute the sum.
    ;;;
    define sumlist( L ); lvars L;
        applist( 0, L, nonop + )
    enddefine;
    
Now we are in a position to compute the answers.  We simply select the 
members of the powerlist of [ 1 3 4 7 8 2 9] that sum to 13 ....

    vars answers =
        select( power_list( [ 1 3 4 7 8 2 9] ), sumlist <> nonop ==#(% 13 %) );

This is a nice one-liner.  Of course, we would like to see the solutions ...

    : answers.hd =>
    ** [8 4 1]
    : answers.length =>
    ** 6
    : answers =>
    ** [[8 4 1] [2 8 3] [2 7 3 1] [2 7 4] [9 4] [9 3 1]]
    :

Well, it amused me (and found a run-time bug in Poplog) ...

Steve