PreviousUpNext

15.4.1119  src/lib/std/src/list.pkg

## list.pkg
#
# List(X) type and core operations on lists.
#
# See also:
#
#     src/lib/std/src/paired-lists.pkg
#     src/lib/src/list-mergesort.pkg

# Compiled by:
#     src/lib/std/src/standard-core.sublib


# The following are defined in
#
#     src/lib/core/init/pervasive.pkg
#
# and consequently available unqualified
# at top level:
#
#   type List
#   my NIL, ! , hd, tl, null, length, @, apply, map, fold_backward, fold_forward, reverse
#
# The following are defined in this file 
# and consequently not available unqualified
# at top level:
#
#   exception EMPTY
#   my last, nth, take_n, drop_n, cat, reverse_and_prepend, map_partial_fn, find, filter,
#       partition, exists, all, tabulate
#
# The following infix declarations will hold at top level:
#   infixr 60 ! @



###                         "One can even conjecture that Lisp
###                          owes its survival specifically to
###                          the fact that its programs are lists,
###                          which everyone, including me,
###                          has regarded as a disadvantage."
###
###                                 -- John McCarthy, "Early History of Lisp"




package   list
: (weak)  List                                  # List          is from   src/lib/std/src/list.api
{                                               # inline_t      is from   src/lib/core/init/built-in.pkg
    my (+)  = inline_t::default_int::(+);
    my (-)  = inline_t::default_int::(-);
    my (<)  = inline_t::default_int::(<);
    my (<=) = inline_t::default_int::(<=);
    my (>)  = inline_t::default_int::(>);
    my (>=) = inline_t::default_int::(>=);

#     op =  = inline_t::(=) 

    List == List;                                                       # Import List into this package from   src/lib/core/init/pervasive.pkg

    exception EMPTY = EMPTY;

    null = null;
    head = head;
    tail = tail;

    fun last []      =>  raise exception EMPTY;                         # Return last element in list.                          Raise EMPTY if list is empty.
        last [x]     =>  x;
        last (_ ! r) =>  last r;
    end;

    fun get_item []      =>  NULL;
        get_item (x ! r) =>  THE (x, r);
    end;

    fun nth (l, n)                                                      # Return n-th    element  from list.  Raise INDEX_OUT_OF_BOUNDS if list is not long enough.
        =
        {   fun loop ((e ! _), 0) => e;
                loop ([], _) => raise exception INDEX_OUT_OF_BOUNDS;
                loop ((_ ! t), n) => loop (t, n - 1);
            end;

            if (n >= 0)   loop (l, n);
            else          raise exception INDEX_OUT_OF_BOUNDS;
            fi;
        };

    fun take_n (l, n)                                                   # Return first N elements from list.  Raise INDEX_OUT_OF_BOUNDS if list is not long enough.
        =
        if (n >= 0)   loop (l, n);
        else          raise exception INDEX_OUT_OF_BOUNDS;
        fi
        where
            fun loop (l,       0) =>  [];
                loop ([],      _) =>  raise exception INDEX_OUT_OF_BOUNDS;
                loop ((x ! t), n) =>  x ! loop (t, n - 1);
            end;
        end;

    fun drop_n (l, n)                                                   # Drop first N elements from list, return remainder.     Raise INDEX_OUT_OF_BOUNDS if list is not long enough.
        =
        if (n >= 0)   loop (l, n);
        else          raise exception INDEX_OUT_OF_BOUNDS;
        fi
        where
            fun loop (l,       0) =>  l;
                loop ([],      _) =>  raise exception INDEX_OUT_OF_BOUNDS;
                loop ((_ ! t), n) =>  loop (t, n - 1);
            end;
        end;

    fun split_n (l, n)
        =
        {   if (n < 0)   raise exception INDEX_OUT_OF_BOUNDS;   fi;
            #
            split_n' (l, n);
        }
        where
            fun split_n' (l, 0)
                    =>
                    ([], l);

                split_n' (a ! rest, n)
                    =>
                    {   (split_n' (rest, n - 1))
                            ->
                            (p, s);

                        (a ! p, s);
                    };

                split_n' _ =>   raise exception INDEX_OUT_OF_BOUNDS;
            end;
        end;
    

    length  =  length;
    reverse =  reverse;

#    my op (@) = op (@);
#
# The above stopped working, so the below replicates the original definition XXX BUGGO FIXME
#
    fun l1 @ l2
        =
        fold_backward (!) l2 l1;

    fun cat []      =>   [];
        cat (l ! r) =>   l @ cat r;
    end;

# list-fns had the following as its equivalent
# to 'cat' -- is it fundamentally more efficient
# than (or just more vebose than) the above?  -- 2012-03-19 CrT
#
#    fun flatten []
#           =>
#           [];
#
#        flatten [l]
#           =>
#           l;
#
#        flatten ll
#           =>
#           flat (ll, [])
#           where
#               fun flat ([],     l) =>  reverse l;
#                   flat (ll ! r, l) =>  flat (r, flat2 (ll, l));
#               end
#
#               also
#               fun flat2 ([],    l) =>  l;
#                   flat2 (x ! r, l) =>  flat2 (r, x ! l);
#               end;
#           end;
#    end;



    fun reverse_and_prepend ([],     l) =>  l;                                  # Return result of prepending reversed first arg to untouched second arg.
        reverse_and_prepend (h ! t,  l) =>  reverse_and_prepend (t, h ! l);
    end;

    fun repeat  (list: List(X),  i: Int):       List(X)                         # Return result of concatenating 'i' copies of 'list'.
        =
        repeat' (i, [])
        where
            fun repeat' (i, result)
                =
                if (i <= 0)   cat result;
                else          repeat' (i - 1,  list ! result);
                fi;     
        end;




    apply   =  apply;
    map     =  map;

    apply'  =  apply';
    map'    =  map';


    fun map_partial_fn fn l
        =
        mapp (l, [])
        where 
            fun mapp ([], l)
                    =>
                    reverse l;

                mapp (x ! r, l)
                    =>
                    case (fn x)
                        #                      
                        THE y =>  mapp (r, y ! l);
                        NULL  =>  mapp (r, l);
                    esac;
            end;
        end;


    # Return first list element satisfying given predicate else NULL:
    #
    fun find predicate []
            =>
            NULL;

        find predicate (a ! rest)
            =>
            if (predicate a)   THE a;
            else               find predicate rest;
            fi;
    end;


    # Return all list elements EXCEPT first element satisfying given predicate:
    #
    fun remove_first  predicate
        =
        rm
        where
            fun rm [] =>   [];

                rm (a ! l)
                    =>
                    if (predicate a)    l;
                    else                a ! (rm l);
                    fi;
            end;
        end;


    # Return list elements satisfying given predicate:
    #
    fun filter predicate []
            =>
            [];

        filter predicate (element ! rest)
            =>
            if (predicate element)   element ! (filter predicate rest); 
            else                               (filter predicate rest);
            fi;
    end;

    # Return list elements NOT satisfying given predicate:
    #
    fun remove predicate []
            =>
            [];

        remove predicate (element ! rest)
            =>
            if (predicate element)             (remove predicate rest);
            else                     element ! (remove predicate rest); 
            fi;
    end;

    fun partition predicate l
        =
        loop (l,[],[])
        where
            fun loop ([], true_list, false_list)
                    =>
                   (reverse true_list, reverse false_list);

                loop (h ! t,  true_list,  false_list)
                    => 
                    if (predicate h)    loop (t,  h ! true_list,      false_list);
                    else                loop (t,      true_list,  h ! false_list);
                   fi;
            end;
        end;

    fun split_at_first  predicate
        =
        spl
        where
            fun spl (l as a ! rest)
                    =>
                    if (predicate a)
                        #
                        ([], l);
                    else
                        (spl rest) ->   (p, s);

                        (a ! p, s);
                    fi;

                spl [] =>   ([], []) ;
            end;
        end;


    fun prefix_to_first  predicate  l                   # All elements up to first matching predicate.
        =
        #1 (split_at_first  predicate  l);


    fun suffix_from_first predicate []                  # All elements after first matching predicate.
            =>
            [];

        suffix_from_first predicate (a ! rest)
            =>
            if (predicate a)   rest;
            else               suffix_from_first predicate rest;
            fi;
    end;



    fold_backward =  fold_backward;
    fold_forward  =  fold_forward;

    fun exists predicate
        =
        f
        where
            fun f []      =>  FALSE;
                f (h ! t) =>  predicate h or f t;
            end;
        end;

    fun all predicate
        =
        f
        where
            fun f []      =>  TRUE;
                f (h ! t) =>  predicate h and f t;
            end;
        end;

    fun from_fn (len, genfn)
        = 
        {   if (len < 0)    raise exception SIZE;       fi;
            #
            loop 0
            where
                fun loop n
                    =
                    if (n == len)   [];
                    else            (genfn n) ! (loop (n+1));
                    fi;
            end;   
        };

    fun compare_sequences compare
        =
        loop
        where
            fun loop ([], []) =>  EQUAL;
                loop ([], _)  =>  LESS;
                loop (_, [])  =>  GREATER;

                loop (x ! xs,   y ! ys)
                    =>
                    case (compare (x, y))
                        #                       
                        EQUAL   =>  loop (xs, ys);
                        unequal =>  unequal;
                    esac;
            end;
        end;

    fun drop (dropme, list)                                             # Return given list with all copies of 'dropme' removed.
        =
        drop' list
        where
            fun drop' []
                    =>
                    [];

                drop' (x ! rest)
                    =>
                    if (x == dropme)         drop' rest;
                    else               x  !  drop' rest;
                    fi;
            end;
        end;

    fun a in []            =>  FALSE;
        a in (this ! rest) =>  (a == this)  or  (a in rest);
    end;
        #
        # 2008-03-25 CrT:
        #    This function is inspired by the similar Python operator;
        #    I changed Mythryl syntax to make 'in' not be a reserved
        #    word specifically for this function.  :)
        #    I was originally going to put the above fun def in
        #        src/lib/core/init/pervasive.pkg
        #    but that resulted in
        #        bin/mythryl-runtime-intel32: Fatal error -- unable to find picklehash (compiledfile identifier) '[4500880824c70d26c741e5b186aad4c1]'
        #        sh/make-compiler-executable:   Compiler link failed, no mythryld executable
        #    which I didn't feel like trying to understand.
        #    So I settled for defining 'in' as infix in pervasive.pkg,
        #    defining it here, and exporting it as a scripting global in
        #        src/app/makelib/main/makelib-g.pkg
        #    I'd still rather have it in pervasive.pkg, though,
        #    or otherwise made generally available as a global:  XXX SUCKO FIXME.
        #
        # 2009-09-15 CrT:
        #    The core issue appears to be the attempt to use
        #    typeagnostic in/equality testing in pervasive.pkg.


}; #  package list 




Comments and suggestions to: bugs@mythryl.org

PreviousUpNext