[m-users.] Problems with store and mostly unique/unique predicates.

Bartosz Witkowski bartosz.witkowski at like-a-boss.net
Sun Feb 9 00:34:52 AEDT 2014


Hello,

On Sat, Feb 8 2014, Mark Brown wrote:
>
> In the context you gave earlier, those predicates wouldn't be the
> same. If p1 or p2 fail, then the A value is destroyed and gone
> forever. On the other hand, if p2 or p2c return 'no' they still have
> to return an A value in the final argument, which will then be the one
> used in the else branch.
>
> [...]
>
> Julien's option (1) can also be applied if you have your own means of
> rolling back any changes prior to failing (like a transaction
> journal).
>

Oh, I understand now. You are right of course - I misunderstood the universal
case because in my *special* case the semidet predicate will fail before making
any changes to the state.

Mark, Julien thank you very much for your help and for your time!

Regards,
Bartosz Witkowski

On Sat, Feb 8, 2014 at 1:50 AM, Mark Brown <mark at mercurylang.org> wrote:
> Hi Bartosz,
>
> On Sat, Feb 8, 2014 at 9:26 AM, Bartosz Witkowski
> <bartosz.witkowski at like-a-boss.net> wrote:
>> Julien,
>>
>> Thank you very much for your input - I just want to make sure I understand this.
>>
>> On Fri, 7 Feb 2014, Julien Fischer wrote:
>>> No, since that would mean that updates to the value in the stored would need to
>>> be undone upon backtracking and that is not possible without trailing.  There's
>>> a trailed store module in extras/trailed_update/tr_store.m if you are after
>>> that kind of thing.  (Since trailing is an optional feature, the standard
>>> library module are not allowed to use it -- we require them to work in all
>>> grades.)
>>
>> I don't understand what is so special about trailing (in this instance).
>> Correct me if I'm wrong but a (incorrect predicate):
>>
>>   :- pred p1(A::di, A::uo) is semidet.
>>
>> can be converted to a:
>>
>>   :- pred p1c(bool::out, A::di, A::uo) is det.
>>
>> one. Similarly
>>
>>   % incorrect
>>   :- pred p2(B1::out, B2::out, A::di, A::uo) is semidet.
>>
>> Can be converted to:
>>
>>   :- pred p2c(maybe({B1, B2})::out, A::di, A::uo) is det.
>>
>> I am probably simplifying much and not understanding the whole problem
>> but at least when the problem is using `store` it should always be
>> possible with this simple conversion. Am I wrong or missing something?
>
> In the context you gave earlier, those predicates wouldn't be the
> same. If p1 or p2 fail, then the A value is destroyed and gone
> forever. On the other hand, if p2 or p2c return 'no' they still have
> to return an A value in the final argument, which will then be the one
> used in the else branch.
>
>>
>>> > 2. Is it possible to mix mostly-unique code with unique code (or does
>>> > mostly-unique code "infect" everything it touches)?
>>> That depends on what you mean by "mix".  (In principle, it's ok so long
>>> as you don't try to nest unique and mostly-unique values.)
>>
>> By mixing I meant is there a way to "turn" a mdi argument into a `uo` one.
>>
>> I initially thought that trying to backtrack on a `di` variable would promote it
>> to a `mdi` one but now, after your explenations, I think that my previous
>> interpretation is incorrect.
>>
>> To reiterate what you said in the previous e-mail - if you try to backtrack the
>> compiler expects a mostly-unique variable not a unique-one. Such "mixing" is
>> thus inpossible - you *need* to have a mostly-unique instantiated variable and
>> hacks aside it's not possible to turn it into a unique one. Is this correct?
>
> Yes.
>
>>
>>> What can you do about this?
>>>
>>> (1) if semi_pred/2 does not actually update !A then you could use a unique-input (ui)
>>> mode in the semidet predicate, e.g.
>>>
>>>     uses_semi(!A) :-
>>>        pred1(A!),
>>>        ( if semi_pred(!.A) then
>>>        true
>>>        else
>>>       true
>>>        ),
>>>       pred2(!A)
>>>
>>>     :- pred semi_pred(A::ui) is semidet.
>>>
>>> (2) if semi_pred/2 is intended to update the state represented by !A then using
>>> unique modes is the wrong thing to do and you should be using mostly-unique modes
>>> (and a compilation grade that supports trailing).
>>
>> Unfortunately, I'm dealing with the second case. I think I could manage
>> to turn the predicate into a `det` one using an auxiliary variable
>> (using the method I described previously) - which while cumbersome is
>> doable.
>>
>> Then again using the tr_store could be a much better option.
>
> These have different meanings, so you need to figure out which is
> correct for your situation. If, in the case that semi_pred fails, you
> need to ensure that the A value is back in its original state, then
> the tr_store approach would work.
>
> Julien's option (1) can also be applied if you have your own means of
> rolling back any changes prior to failing (like a transaction
> journal).
>
> Cheers,
> Mark
>
>>
>> Regards,
>> Bartosz Witkowski
>>
>> On Fri, Feb 7, 2014 at 3:24 AM, Julien Fischer <jfischer at opturion.com> wrote:
>>>
>>> Hi,
>>>
>>>
>>> On Fri, 7 Feb 2014, Bartosz Witkowski wrote:
>>>
>>>> Hello, Mercury-users!
>>>>
>>>> I'm having a bit of a problem with mostly-unique/unique modes and I'm
>>>> wondering if you could help me.
>>>>
>>>> Is code similar to https://gist.github.com/bartosz-witkowski/8854480
>>>> possible in mercury?
>>>
>>>
>>> In short: no, that code contains a mode error (see below).
>>>
>>>
>>>> My use case is a little more complicated but in the end I want to use
>>>> `store' from the stdlib - it seems that predicates that work on store
>>>> are only defined with unique insts (and not mostly-unique insts).
>>>>
>>>> I tried to find ways to convert a `mdi` argument to `uo` one but there
>>>> doesn't seem to be an easy way (`unsafe_promise_unique` only works on
>>>> `in` inst arguments, and is to my understanding *unsafe* anyways).
>>>>
>>>> In the end I'm wondering/searching for:
>>>> 1. Should the stdlib store have predicates that work on mdi insts?
>>>
>>>
>>> No, since that would mean that updates to the value in the stored would need
>>> to
>>> be undone upon backtracking and that is not possible without trailing.
>>> There's
>>> a trailed store module in extras/trailed_update/tr_store.m if you are after
>>> that kind of thing.  (Since trailing is an optional feature, the standard
>>> library module are not allowed to use it -- we require them to work in all
>>> grades.)
>>>
>>>
>>>> 2. Is it possible to mix mostly-unique code with unique code (or does
>>>> mostly-unique code "infect" everything it touches)?
>>>
>>>
>>> That depends on what you mean by "mix".  (In principle, it's ok so long
>>> as you don't try to nest unique and mostly-unique values.)
>>>
>>>
>>>> 3. Ways to solve my problem ;)
>>>
>>>
>>> The key thing to note in understanding this problem is the following
>>> sentence
>>> from the ``Destructive update'' section of the reference manual:
>>>
>>>       Note that a value is not considered 'unique' if it might be
>>>       needed on backtracking.
>>>
>>> Here is the predicate uses_semi/2 with the state variables expanded
>>> (I've done that because it makes it easier to describe what is happening):
>>>
>>>    :- pred uses_semi(A::di, A::uo) is det.
>>>
>>>    uses_semi(A0, A) :-
>>>        pred1(A0, A1),
>>>        ( if semi_pred(A1, A2) then
>>>            A3 = A2
>>>        else
>>>            A3 = A1
>>>        ),
>>>        pred2(A3, A).
>>>
>>> The else branch requires the value A1 if the condition of the if-then-else
>>> fails (i.e. if the call to semi_pred/2 backtracks).  However, the language
>>> definition says that the value A1 *cannot* be considered to be unique of
>>> semi_pred/2 backtracks.  It can be inferred to be mostly-unique, but that
>>> differs from the inst declared in the predicate declaration.  That mismatch
>>> is
>>> the error that the compiler is trying to tell you about when it prints:
>>>
>>>     mtest.m:030: In clause for `uses_semi(di, uo)':
>>>     mtest.m:030:   in argument 1 of call to predicate `mtest.semi_pred'/2:
>>>     mtest.m:030:   mode error: variable `STATE_VARIABLE_A_6' has
>>> instantiatedness
>>>     mtest.m:030:   `mostly_unique',
>>>     mtest.m:030:   expected instantiatedness was `unique'.
>>>
>>> (If you compile my version of the predicate the error message is little
>>> clearer
>>> since it talks about `A1' instead of the variable introduced by state
>>> variable
>>> expansion.)
>>>
>>> What can you do about this?
>>>
>>> (1) if semi_pred/2 does not actually update !A then you could use a
>>> unique-input (ui)
>>> mode in the semidet predicate, e.g.
>>>
>>>    uses_semi(!A) :-
>>>       pred1(A!),
>>>       ( if semi_pred(!.A) then
>>>           true
>>>       else
>>>           true
>>>       ),
>>>      pred2(!A)
>>>
>>>    :- pred semi_pred(A::ui) is semidet.
>>>
>>> (2) if semi_pred/2 is intended to update the state represented by !A then
>>> using
>>> unique modes is the wrong thing to do and you should be using mostly-unique
>>> modes
>>> (and a compilation grade that supports trailing).
>>>
>>> Cheers,
>>> Julien.
>> _______________________________________________
>> users mailing list
>> users at lists.mercurylang.org
>> http://lists.mercurylang.org/listinfo/users



More information about the users mailing list