[mercury-users] Re: Re: Mercury users list.....

Ralph Becket rafe at cs.mu.OZ.AU
Fri Oct 11 10:30:12 AEST 2002


Noel  Pinto, Thursday, 10 October 2002:
> 
> I had registered myself with majordomo. It had also sent mails for 
> confirming it with some comands, which I did. Just after I 
> recieved your mail I had sent one mail filled with few queries to 
> the list.
> 
> I still cannot find my queies up on the mercury mailing list esp. 
> after 4 hrs. Should I try registering again??

That's odd.  Please try again and I'll see what majordomo says in its
log file.

> I want to accept the users name and display hi (user's name) on 
> the screen. But I get errors... Plz let me know where I could go 
> wrong and how.
>
> :- module first_file.
> :- interface.
> 
> :- import_module io.
> :- pred main(io__state, io__state).
> :- mode main(di, uo) is det.

You can shorten

:- pred main(io__state, io__state).

to just

:- pred main(io, io).

We introduced `io' in the io module as a synonym for `state'; it's
shorter and arguably a little bit more readable.

> :- implementation.
> 
> :- import_module char.

You should also import `string' since you use strings.

> main -->
> 	io__write_string("Enter your name \n"), 
>	io__read_word(H),
>       {disp(H, name)}.

This is a little confused.

First thing: you're better off not using DCGs until you really feel
comfortable with passing the IO state around.

Second thing: once you are comfortable with doing so, use state variable
syntax rather than DCGs.  The reason why lots of old code uses DCGs was
that we didn't have a good alternative; it's actually bad style because
DCG notation wasn't intended for passing IO states around.

So here's your code for main/2 written out long-hand:

main(IO0, IO) :-
	io__write_string("Enter your name\n", IO0, IO1),
	io__read_word(H, IO1, IO2),
	disp(H, name),
	IO = IO2.

The call to io__write_string/3 is fine.

Then we hit a number of problems.

io__read_word/3 returns an io__result(list(char)) in its first argument.

io__result/1 has three constructors:

- ok(X)
- eof
- error(E)

and you need to handle them before you get the data back.

The easiest way of doing this is to use an if-then-else and report a
problem if you didn't get an ok(X) back.

The next problem is your call `{ disp(H, name) }'.  The braces simply
mean "don't insert the hidden DCG arguments here", which is certainly
not what you want since disp has to do some output and hence needs the
IO state.  You need to get rid of them.  Another problem is the argument
`name' which isn't defined anywhere.  Let's get rid of `name' (since we
don't really need it) and rewrite your main/2 predicate:

	% The require module supplies the error/1 predicate.
	%
:- import_module char, string, require, list.

main(IO0, IO) :-
	io__write_string("Enter your name\n", IO0, IO1),
	io__read_word(Result, IO1, IO2),
	( if Result = ok(Chars) then
		disp(Chars, IO2, IO)
	  else
		error("unexpected eof or read error")
	).

error/1 always throws an exception; the compiler can see this from the
determinism of error/1 (`erroneous') and therefore does not insist that
we make sure that IO is bound at the end of the `else' arm of the
if-then-else.

> :- pred disp(char :: in, char :: out) is det.
> 
> disp(H, N) -->
>         io__write_string("Enter your name : \n"),
>         io__read_word(H),
>         { if H = ok([FirstChar|_]), char__to_upper,'')
>         then io__write_string("Hi \n"),
>         io__write_string(H)
>         else
>         io__write_string("Bye \n")}.

Your type declaration is wrong.  It's also probably better not to mix
type and mode declarations in the same line.

To start off with, the first argument is going to be a list(char) as we
can see from the type of io__read_word.  You have given it type char.

The argument N isn't used anywhere.

You've duplicated the first two lines of main/2 inside disp/4.

You've { escaped } the entire if-then-else when parts of it need the IO
state, but this means they won't see it.

You have a mysterious extra closed parenthesis at the end of the
condition of the if-then-else.

You declare H to have type char, but then unify it with something of
type io__result(list(char)).

You're using lists, but haven't imported the list module.

What is the call to char__to_upper (with no arguments) supposed to
achieve?  Ditto for the call to '' (this is the name we reserve for
higher order application; you're not meant to use it directly.)

Here's the code that fixes these problems:

:- pred disp(list(char), io, io).
:- mode disp(in,         di, uo) is det.

disp(NameChars, IO0, IO) :-
	( if NameChars \= [] then
		io__write_string("Hi ", IO0, IO1),
		io__write_string(string__from_char_list(NameChars), IO1, IO2),
		io__write_string("\n", IO2, IO)
	  else
	  	io__write_string("Bye\n", IO0, IO)
	).

It's easier to use the function string__from_char_list/1 from the string
module than to print out each char separately.

We can recode all of this using state variable syntax, which handles all
the input/output argument pairs and variable numbering thereof:

main(!IO) :-
	io__write_string("Enter your name\n", !IO),
	io__read_word(Result, !IO),
	( if Result = ok(Chars) then
		disp(Chars, !IO)
	  else
		error("unexpected eof or read error")
	).

:- pred disp(list(char), io, io).
:- mode disp(in,         di, uo) is det.

disp(NameChars, !IO) :-
	( if NameChars \= [] then
		io__write_string("Hi ", !IO),
		io__write_string(string__from_char_list(NameChars), !IO),
		io__write_string("\n", !IO)
	  else
	  	io__write_string("Bye\n", !IO)
	).

Hopefully it's obvious how the state variable code transforms into the
non-state variable code.

In short,
- you need to take more care over syntax;
- you have to look carefully at the types involved.

Finally, here's the short way of writing your program:

:- import_module string, list, require.

main(!IO) :-
	io__format("Enter your name: ", !IO),
	io__read_line_as_string(Result, !IO),
	( if Result = ok(Name) then
		( if string__length(Name) > 1 then
			io__format("Hi %s", [s(Name)], !IO)
		  else
		  	io__format("Bye\n", !IO)
		)
	).

The reason why we test for `string__length(Name) > 1' is that
io__read_line_as_string also includes the newline character at the end
of the input.

Hope this helps,

Ralph
--------------------------------------------------------------------------
mercury-users mailing list
post:  mercury-users at cs.mu.oz.au
administrative address: owner-mercury-users at cs.mu.oz.au
unsubscribe: Address: mercury-users-request at cs.mu.oz.au Message: unsubscribe
subscribe:   Address: mercury-users-request at cs.mu.oz.au Message: subscribe
--------------------------------------------------------------------------



More information about the users mailing list