[mercury-users] Destructive map_replace

Michael Day mikeday at yeslogic.com
Mon Jan 5 19:31:28 AEDT 2009


Here is a C implementation of map_replace, changed to return a boolean 
result instead of a maybe, to simplify the C code and reduce allocation:

:- pred replace_foo(string, list(string), bool).
:- mode replace_foo(ui, uo, out) is det.

replace_foo(X, Xs, Res) :-
     ( if X = "foo" then
         copy(["bar"], Xs),
         Res = yes
     else
         Xs = [],
         Res = no
     ).

:- pred call_pred(pred(T, list(T), bool), T, list(T), bool).
:- mode call_pred(in(pred(ui, uo, out) is det), ui, uo, out) is det.

call_pred(Pred, X, Xs, Res) :- Pred(X, Xs, Res).

:- pragma foreign_export(c, call_pred(in(pred(ui, uo, out) is det), ui, 
uo, out), "call_pred").

:- pred map_replace(pred(T, list(T), bool), list(T), list(T)).
:- mode map_replace(in(pred(ui, uo, out) is det), di, uo) is det.

:- pragma foreign_proc(c,
         map_replace(Pred::in(pred(ui, uo, out) is det), Xs::di, Ys::uo),
         [will_not_call_mercury, thread_safe, promise_pure], "
     {
         MR_Word *AddrOfPrev;

         Ys = Xs;
         AddrOfPrev = &Ys;

         while (!MR_list_is_empty(Xs))
         {
             MR_Integer X = (MR_Integer) MR_list_head(Xs);
             MR_Word Xs0 = (MR_Word) MR_list_tail(Xs);
             MR_Word NewXs;
             MR_Word Res;
             MR_Word Fake;

             call_pred(Fake, Pred, X, &NewXs, &Res);

             if (Res != 0)
             {
                 if (MR_list_is_empty(NewXs))
                 {
                     *AddrOfPrev = Xs0;
                 }
                 else
                 {
                     *AddrOfPrev = NewXs;

                     do
                     {
                         Xs = NewXs;
                         NewXs = (MR_Word) MR_list_tail(NewXs);
                     }
                     while (!MR_list_is_empty(NewXs));

                     MR_list_tail(Xs) = Xs0;

                     AddrOfPrev = &(MR_list_tail(Xs));
                 }
             }
             else
             {
                 AddrOfPrev = &(MR_list_tail(Xs));
             }

             Xs = Xs0;
         }
     }
").

One question: I'm passing a fake type info to call_pred, and nothing 
seems to go wrong yet, but I feel guilty. Should I be?

Cheers,

Michael

-- 
Print XML with Prince!
http://www.princexml.com
--------------------------------------------------------------------------
mercury-users mailing list
Post messages to:       mercury-users at csse.unimelb.edu.au
Administrative Queries: owner-mercury-users at csse.unimelb.edu.au
Subscriptions:          mercury-users-request at csse.unimelb.edu.au
--------------------------------------------------------------------------



More information about the users mailing list