Re: Newbies question

From: Gerd Stolpmann (Gerd.Stolpmann@darmstadt.netsurf.de)
Date: Sat Oct 02 1999 - 20:04:48 MET DST


From: Gerd Stolpmann <Gerd.Stolpmann@darmstadt.netsurf.de>
To: Peter Bruhn <bruhn@isis.wu-wien.ac.at>
Subject: Re: Newbies question
Date: Sat, 2 Oct 1999 20:04:48 +0200
Message-Id: <99100220441000.05156@ice>

> let read_res file : ('a * 'b) list =
> let final_result = ref [] in
> let fd = open_in file in
> try
> let lexbuf = Lexing.from_channel fd in
> while true do
> let result = Parseres.main Lexres.token lexbuf in
> final_result := result :: !final_result
> done (* <---- nothing returned here, but we cannot get here anyway
> the loop is exited by an exception only *)

No, this is not true. "()", the only element of the "unit" type would be
returned if the loop could be finished; every "while" loop returns "()" by
definition. The compiler does not detect the infinite loop, so the typing
constraint applies that the code within "try" must be compatible with the
"unit" type.

> with
> Lexres.Eof ->
> close_in fd; !final_result (* !final_result is of type ('a * 'b) list *)
> | Parsing.Parse_error ->
> close_in fd; printf "ERROR: Ressourcen Datei fehlerhaft\n"; exit (-1);

The whole "try ... with ..." construct enforces the typing constraint that the
type of the "try" expression and all types of the "with" expressions must be
compatible. As already pointed out, the "try" expression has unit type; the
"Lexres.Eof" branch has the mentioned list type; and the "Parsing.Parse_error"
branch has arbitrary type (because the "exit" function has type int -> 'a).
The unit type and the list type cannot be unified, so a typing error occurs.

>
>But when I use an empty list after the endless-loop, it works alright. Do I
>really have to fake the compiler? Or am I doing something wrong? This works:
>
> let read_res file : ('a * 'b) list =
> let final_result = ref [] in
> let fd = open_in file in
> try
> let lexbuf = Lexing.from_channel fd in
> while true do
> let result = Parseres.main Lexres.token lexbuf in
> final_result := result :: !final_result
> done; [] (* <---------- EMPTY LIST INSERTED HERE *)

Now the "try" expression has the type 'a list which can be unified with the
types of the "with" expressions.

The problem is that the compiler does not detect that the loop never finishes.
In general, this is impossible to detect because the problem is undecidable.

You are lucky that you can simply form the senseless value []; sometimes this is
not possible (e.g. if the type is abstract). A solution which always works is to
call a function which does not return, e.g.

        while true do ... done; failwith "This cannot happen"

"failwith" is a function with type string -> 'a, i.e. it unifies with every
type.

As "while true do" is a frequent construct, another solution would be to extend
the language by a new

        infinitely do ... done

construct which does the same, but has type 'a instead of unit. As OCaml is not
meant as an imperative language, do not hope that such a feature will be added.

Another possibility is to use an endless recursion:

        let rec read_token () =
           ...;
           read_token()
        in
        try
          read_token()
        with
           ... -> ... | ... -> ... | ...

The result type of the function "read_token" is not constrained at all (type
'a), so it unifies with every other type. This is the solution without tricks,
and it is straight-forward.

Gerd

--
----------------------------------------------------------------------------
Gerd Stolpmann      Telefon: +49 6151 997705 (privat)
Viktoriastr. 100             
64293 Darmstadt     EMail:   Gerd.Stolpmann@darmstadt.netsurf.de (privat)
Germany                     
----------------------------------------------------------------------------



This archive was generated by hypermail 2b29 : Sun Jan 02 2000 - 11:58:25 MET