[m-dev.] Array modes

Peter Wang novalazy at gmail.com
Fri Oct 24 16:06:50 AEDT 2014


Hi,

What do you think about changing the modes in the array module along the
lines shown in the attached file?  Note that we don't need to use
constrained inst vars; they can be replaced by `ground' and `unique'.

The first change is to bring back the bogus insts while (hopefully)
avoiding the problem that caused them to be removed in commit 67bcaf3.
See also
http://www.mercurylang.org/list-archives/developers/2007-February/014642.html


The [intended] modes in the existing array.m don't make sense to me,
e.g.

    :- pred lookup(array(T), int, T).
    %:- mode lookup(array_ui, in, out) is det.

At the end of the call, the array is not unique in its elements as the
third argument shares a reference with one of its elements.

    :- pred set(int, T, array(T), array(T)).
    :- mode set(in, in, array_di, array_uo) is det.

Placing the non-unique value into the array makes it not unique in its
elements.

Peter
-------------- next part --------------
%-----------------------------------------------------------------------------%

:- module array3.
:- interface.

:- type array(T).

    % The following insts are made up.
    %
    % The `empty' constructor is necessary to prevent the compiler assuming
    % that two array values with different insts will never compare equal,
    % which is false when the arrays are empty.
    %
    % The second argument of the `nonempty' constructor approximates the insts
    % of the elements. The first argument represents the number of elements;
    % without it, the compiler may assume that two array values with the same
    % second inst necessarily compare equal.

:- inst array(I)        == bound(empty ; nonempty(ground, I)).
:- inst uniq_array(I)   == unique(empty ; nonempty(ground, I)).

:- pred make_empty_array(array(T)).
:- mode make_empty_array(out(unique(empty))) is det.

    % The array elements are not unique because we don't copy the initialiser.
    %
:- pred unsafe_init(int, T, array(T)).
:- mode unsafe_init(in, in(I), out(uniq_array(I))) is det. % I =< ground

    % Getting the size of an array does not change its uniqueness or the
    % uniqueness of its elements.
    %
:- pred size(array(T), int).
:- mode size(in(uniq_array(I =< unique)), out) is det.
:- mode size(in(array(I)), out) is det.
:- mode size(in, out) is det.

    % Extracting a element from an array makes all of the array's elements
    % not unique.
    %
:- pred unsafe_lookup(array(T), int, T).
:- mode unsafe_lookup(in(uniq_array(I)), in, out(I)) is det. % I =< ground
:- mode unsafe_lookup(in(array(I)), in, out(I)) is det.
:- mode unsafe_lookup(in, in, out) is det.

    % Placing a non-unique value into an array makes the elements not unique.
    %
:- pred unsafe_set(int, T, array(T), array(T)).
% not really usable
% :- mode unsafe_set(in, in(I), di(uniq_array(I)), out(uniq_array(I)))
%     is det.
:- mode unsafe_set(in, in, di(uniq_array(ground)), out(uniq_array(ground)))
    is det.
:- (mode unsafe_set(in, di(I), di(uniq_array(I)), out(uniq_array(I)))
    is det) <= (I =< unique).

%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%

:- implementation.

:- import_module int.

:- pragma foreign_type("C", array(T), "MR_Word *", [can_pass_as_mercury_type])
    where equality is array_equal.

:- pred array_equal(array(T), array(T)).
:- mode array_equal(in, in) is semidet.

%-----------------------------------------------------------------------------%

:- pragma foreign_proc("C",
    make_empty_array(Array::out(unique(empty))),
    [will_not_call_mercury, promise_pure, thread_safe],
"
    Array = MR_GC_NEW_ARRAY(MR_Word, 1);
    Array[0] = 0;
").

%-----------------------------------------------------------------------------%

:- pragma foreign_proc("C",
    unsafe_init(Size::in, Item::in(I), Array::out(uniq_array(I))),
    [will_not_call_mercury, promise_pure, thread_safe],
"
    MR_Integer i;

    Array = MR_GC_NEW_ARRAY(MR_Word, Size + 1);
    Array[0] = Size;
    for (i = 0; i < Size; i++) {
        Array[1 + i] = Item;
    }
").

%-----------------------------------------------------------------------------%

:- pragma foreign_proc("C",
    size(Array::in(uniq_array(I =< unique)), Size::out),
    [will_not_call_mercury, promise_pure, thread_safe],
"
    Size = Array[0];
").

:- pragma foreign_proc("C",
    size(Array::in(array(I)), Size::out),
    [will_not_call_mercury, promise_pure, thread_safe],
"
    Size = Array[0];
").

:- pragma foreign_proc("C",
    size(Array::in, Size::out),
    [will_not_call_mercury, promise_pure, thread_safe],
"
    Size = Array[0];
").

%-----------------------------------------------------------------------------%

:- pragma foreign_proc("C",
    unsafe_lookup(Array::in(uniq_array(I)), Index::in, Elem::out(I)),
    [will_not_call_mercury, promise_pure, thread_safe],
"
    Elem = Array[1 + Index];
").

:- pragma foreign_proc("C",
    unsafe_lookup(Array::in(array(I)), Index::in, Elem::out(I)),
    [will_not_call_mercury, promise_pure, thread_safe],
"
    Elem = Array[1 + Index];
").

:- pragma foreign_proc("C",
    unsafe_lookup(Array::in, Index::in, Elem::out),
    [will_not_call_mercury, promise_pure, thread_safe],
"
    Elem = Array[1 + Index];
").

%-----------------------------------------------------------------------------%

% :- pragma foreign_proc("C",
%     unsafe_set(Index::in, Elem::in(I),
%         Array0::di(uniq_array(I)),
%         Array::out(uniq_array(I))),
%     [will_not_call_mercury, promise_pure, thread_safe],
% "
%     Array = Array0;
%     Array[1 + Index] = Elem;
% ").

:- pragma foreign_proc("C",
    unsafe_set(Index::in, Elem::in,
        Array0::di(uniq_array(ground)),
        Array::out(uniq_array(ground))),
    [will_not_call_mercury, promise_pure, thread_safe],
"
    Array = Array0;
    Array[1 + Index] = Elem;
").

:- pragma foreign_proc("C",
    unsafe_set(Index::in, Elem::di(I =< unique),
        Array0::di(uniq_array(I =< unique)),
        Array::out(uniq_array(I =< unique))),
    [will_not_call_mercury, promise_pure, thread_safe],
"
    Array = Array0;
    Array[1 + Index] = Elem;
").

%-----------------------------------------------------------------------------%

array_equal(A, B) :-
    (
        size(A, Size),
        size(B, Size)
    ->
        elements_equal(A, B, 0, Size)
    ;
        fail
    ).

:- pred elements_equal(array(T), array(T), int, int).
:- mode elements_equal(in(array(I)), in(array(I)), in, in) is semidet.
:- mode elements_equal(in, in, in, in) is semidet.

elements_equal(A, B, Index, Size) :-
    (
        Index = Size
    ->
        true
    ;
        unsafe_lookup(A, Index, Elem),
        unsafe_lookup(B, Index, Elem)
    ->
        elements_equal(A, B, Index + 1, Size)
    ;
        fail
    ).

%-----------------------------------------------------------------------------%
% vim: ft=mercury ts=4 sts=4 sw=4 et


More information about the developers mailing list