getopt.m is impossible to use because det inference fails with "Uncaught Mercury exception"
ulidtko opened this issue · 4 comments
The simplest "hello getopt" code fails to compile:
:- module hello_getopt.
:- interface.
:- import_module io.
:- pred main(io::di, io::uo) is det.
:- implementation.
:- import_module getopt_io.
:- import_module char,string.
main -->
io.command_line_arguments(Argv),
process_options(optDescr, Argv, _, ParsedOpts),
io.print(ParsedOpts).
:- type myoption ---> optFoo; optBar.
:- func optDescr = option_ops(myoption).
optDescr = option_ops(shortOpt, longOpt, defaultOpt).
:- pred shortOpt(char::in, myoption::out).
shortOpt('F', optFoo).
shortOpt('B', optBar).
:- pred longOpt(string::in, myoption::out).
longOpt("foo", optFoo).
longOpt("bar", optBar).
:- pred defaultOpt(myoption::in, option_data::out).
defaultOpt(optFoo, string("buzz")).
defaultOpt(optBar, int(42)).
Error message:
Uncaught Mercury exception:
Software Error: check_hlds.polymorphism: predicate `check_hlds.polymorphism.lambda_modes_and_det'/4: Sorry, not implemented: determinism inference for higher order predicate terms.
Specifying defaultOpt
determinism explicitly does not help; neight does a separate :- mode defaultOpt
declaration.
Since there's no way to use getopt
/getopt_io
APIs while not specifying any default values for options, the library is rendered basically useless.
The Mercury compiler uses getopt_io, and it works just fine. Your code would work too
if you declared the determinism of shortOpt, longOpt and defaultOpt.
@zsomogyi thanks!
Now I get this:
hello.m:013: In clause for `main(di, uo)':
hello.m:013: mode error in conjunction. The next 2 error messages indicate
hello.m:013: possible causes of this error.
hello.m:012: In clause for `main(di, uo)':
hello.m:012: in argument 1 of call to predicate
hello.m:012: `getopt_io.process_options'/6:
hello.m:012: mode error: variable `V_10' has instantiatedness `ground',
hello.m:012: expected instantiatedness was
hello.m:012: `bound(getopt_io.option_ops((pred((ground >> ground), (free >>
hello.m:012: ground)) is semidet), (pred((ground >> ground), (free >>
hello.m:012: ground)) is semidet), (pred((free >> ground), (free >> ground))
hello.m:012: is nondet)) ; getopt_io.option_ops((pred((ground >> ground),
hello.m:012: (free >> ground)) is semidet), (pred((ground >> ground), (free
hello.m:012: >> ground)) is semidet), (pred((free >> ground), (free >>
hello.m:012: ground)) is nondet), (pred((ground >> ground), (ground >>
hello.m:012: ground), (ground >> ground), (free >> ground)) is semidet)) ;
hello.m:012: getopt_io.option_ops_multi((pred((ground >> ground), (free >>
hello.m:012: ground)) is semidet), (pred((ground >> ground), (free >>
hello.m:012: ground)) is semidet), (pred((free >> ground), (free >> ground))
hello.m:012: is multi)) ; getopt_io.option_ops_multi((pred((ground >>
hello.m:012: ground), (free >> ground)) is semidet), (pred((ground >>
hello.m:012: ground), (free >> ground)) is semidet), (pred((free >> ground),
hello.m:012: (free >> ground)) is multi), (pred((ground >> ground), (ground
hello.m:012: >> ground), (ground >> ground), (free >> ground)) is
hello.m:012: semidet)))'.
hello.m:013: In clause for `main(di, uo)':
hello.m:013: in argument 2 of call to predicate `io.print'/3:
hello.m:013: unique-mode error: the called procedure would clobber its
hello.m:013: argument, but variable `STATE_VARIABLE_IO_11' is still live.
code:
:- module hello.
:- interface.
:- import_module io.
:- pred main(io::di, io::uo) is det.
:- implementation.
main -->
io.command_line_arguments(Argv),
process_options(optDescr, Argv, _, ParsedOpts),
io.print(ParsedOpts).
:- import_module getopt_io.
:- import_module char,string.
:- import_module set,map.
:- type myoption ---> optFoo; optBar.
:- func optDescr = option_ops(myoption).
optDescr = option_ops(shortOpt, longOpt, defaultOpt).
:- pred shortOpt(char::in, myoption::out) is semidet.
shortOpt('F', optFoo).
shortOpt('B', optBar).
:- pred longOpt(string::in, myoption::out) is semidet.
longOpt("foo", optFoo).
longOpt("bar", optBar).
:- pred defaultOpt(myoption::in, option_data::out) is det.
defaultOpt(optFoo, string("buzz")).
defaultOpt(optBar, int(42)).
What am I doing wrong now?
You are not looking at other modules that use getopt and getopt_io correctly.
The Mercury distribution has several examples; deep_profiler/mdprof_cgi.m is a simple one.
Have a look, and you should find your problem in no time.
Compiling code for completeness:
:- module hello.
:- interface.
:- import_module io.
:- pred main(io::di, io::uo) is det.
:- implementation.
main -->
io.command_line_arguments(Args),
%{ OptsDescr = optDescr },
process_options(
%OptsDescr,
option_ops_multi(shortOpt, longOpt, defaultOpt),
Args, _, ParsedOpts),
io.print(ParsedOpts).
:- import_module getopt_io.
:- import_module char,string.
:- import_module set,map.
:- type myoption ---> optFoo; optBar.
%:- func optDescr = option_ops(myoption).
%optDescr = option_ops_multi(shortOpt, longOpt, defaultOpt).
:- pred shortOpt(char::in, myoption::out) is semidet.
shortOpt('F', optFoo).
shortOpt('B', optBar).
:- pred longOpt(string::in, myoption::out) is semidet.
longOpt("foo", optFoo).
longOpt("bar", optBar).
:- pred defaultOpt(myoption::out, option_data::out) is multi.
defaultOpt(optFoo, string("buzz")).
defaultOpt(optBar, int(42)).
defaultOpt
has to have (out, out) is multi
mode, and one uses option_ops_multi
instead of option_ops
.
Additionally, 0-ary functions won't help you abbreviate clumsy expressions to a single word; forget beta-equivalence.