[m-users.] Why can't `det` be used where `multi` is expected.
Julian Fondren
jfondren at minimaltype.com
Mon Aug 5 15:46:30 AEST 2019
On 2019-08-04 23:02, Philip White wrote:
> The type [get_opt.option_ops] provides a choice between [option_ops]
> and
> [option_ops_multi], both of which contain short, long, and default
> option predicates. The difference is that [option_ops] expects the
> predicate for default option values to be [nondet], but
> [option_ops_multi] expects it to be [multi].
>
> Below, my predicate, [option_default/2], is declared as [multi], and
> this whole program compiles. However, [option_default/2] is clearly
> deterministic, and indeed the compiler warns that I could be more
> specific. However, if I take the suggestion, then I get nasty
> instantiatedness errors. It would seem to me that passing a
> deterministic predicate into a place which expects a [multi] predicate
> is always valid. What am I not understanding?
"One solution" is a subset of "one or more solutions", but
backtracking never needs to ask a det predicate for its other
solutions. So there's some machinery that's warranted in one case
but not the other. That may be why the language can't silently
promote a det predicate into a multi predicate.
That aside, I'd say the instantiatedness errors are pretty clear
here.
mds.m:022: in argument 1 of call to predicate
`getopt.process_options'/4:
mds.m:022: mode error: variable `OptionOps' has instantiatedness
mds.m:022: unique(
mds.m:022: option_ops_multi(
mds.m:022: /* unique */ (pred(in, out) is semidet),
mds.m:022: /* unique */ (pred(in, out) is semidet),
mds.m:022: /* unique */ (pred(out, out) is det)
mds.m:022: )
mds.m:022: ),
So you're passing an option_ops_multi/3 type that contains three
predicates of those modes. The third one is your det version of
option_default/2.
mds.m:022: expected instantiatedness was
mds.m:022: named inst getopt.option_ops,
Let's go look at that in the module documentation:
:- inst option_ops for option_ops/1
---> option_ops(
pred(in, out) is semidet, % short_option
pred(in, out) is semidet, % long_option
pred(out, out) is nondet % option_default
)
; option_ops_multi(
pred(in, out) is semidet, % short_option
pred(in, out) is semidet, % long_option
pred(out, out) is multi % option_default
)
; option_ops(
pred(in, out) is semidet, % short_option
pred(in, out) is semidet, % long_option
pred(out, out) is nondet, % option_default
pred(in, in, in, out) is semidet % special
handler
)
; option_ops_multi(
pred(in, out) is semidet, % short_option
pred(in, out) is semidet, % long_option
pred(out, out) is multi, % option_default
pred(in, in, in, out) is semidet % special
handler
).
The rest of the error reads a lot like this inst declaration.
You're providing an option_ops_multi/3 with a 'det' third
predicate, but the only options_ops_multi/3 that the 'getopt'
module will accept has a 'multi', not det. So, absent something like
the silent promotion of det to multi that you ask about, there's an
error.
It's not that it's impossible to use det predicates, just that this
module isn't written to accept them.
You can make the warning go away by adding this pragma:
:- pragma no_determinism_warning(option_default/2).
from
https://mercurylang.org/information/doc-latest/mercury_ref/No-determinism-warnings.html
One reason to leave it as 'multi' is that it's probably a law of
the universe that CLI interfaces gain options over time. You've got
stars, but what about different Unicode stars? What about different
colors of star? What about an option to slowly rather than
instantly draw the stars?
Frozen in time, it looks like an error for a multi predicate to be
obviously deterministic. So you wouldn't want to frame code like
that for display in a museum. People will ask questions. But code
is more often in motion.
More information about the users
mailing list