caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
* Newbies question
@ 1999-10-01 13:01 Peter Bruhn
  1999-10-02 18:04 ` Gerd Stolpmann
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Peter Bruhn @ 1999-10-01 13:01 UTC (permalink / raw)
  To: caml-list

The following function does not compile, since the compiler thinks it has
the wrong return type: 

    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 *) 
      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);
          
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 *)
      with 
        Lexres.Eof ->
          close_in fd; !final_result
      | Parsing.Parse_error ->
          close_in fd; printf "ERROR: Ressourcen Datei fehlerhaft\n"; exit (-1);
          
Thanks for any comments, hints, flames, ...
Peter
-------------------
bruhn@wu-wien.ac.at




^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: Newbies question
  1999-10-01 13:01 Newbies question Peter Bruhn
@ 1999-10-02 18:04 ` Gerd Stolpmann
  1999-10-03 10:58 ` Markus Mottl
  1999-10-04 13:37 ` Xavier Leroy
  2 siblings, 0 replies; 4+ messages in thread
From: Gerd Stolpmann @ 1999-10-02 18:04 UTC (permalink / raw)
  To: Peter Bruhn; +Cc: caml-list

>    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                     
----------------------------------------------------------------------------




^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: Newbies question
  1999-10-01 13:01 Newbies question Peter Bruhn
  1999-10-02 18:04 ` Gerd Stolpmann
@ 1999-10-03 10:58 ` Markus Mottl
  1999-10-04 13:37 ` Xavier Leroy
  2 siblings, 0 replies; 4+ messages in thread
From: Markus Mottl @ 1999-10-03 10:58 UTC (permalink / raw)
  To: Peter Bruhn; +Cc: OCAML

>     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 *) 
>       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);

>From the type checker's point of view there are three possible ways out
of your program, but just two can really happen at runtime:

The two exception cases: the first one returns a list of tuples, the second
one exits the program - as you see in the pervasives, "exit" has return
type 'a, so it unifies with any other type (e.g. your tuple list).

Then there is this loop: because there is no return value after it,
it has type "unit" as loops generally do. But "unit" does not unify with a
tuple list.

> 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:

Empty lists have type 'a list - this unifies with a tuple list, of course,
and pleases the type checker.

This is perfectly ok, but if you object to this style, you might as well
use a recursive function to parse the input. If you catch exceptions
within it, you can bail out of the recursion at anytime with the final
result.  Thus, there is no need for any extra constructs to please the
type checker and you also don't need any references for accumulating
the final result - just pass on the intermediate result as a parameter
to the recursive function.

By the way, you might also want to use an exception instead of "exit" to
get out of your program. E.g.: failwith "incorrect resource file"

This would allow the calling function to react more appropriately to
such exceptional conditions.

Best regards,
Markus

-- 
Markus Mottl, mottl@miss.wu-wien.ac.at, http://miss.wu-wien.ac.at/~mottl




^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: Newbies question
  1999-10-01 13:01 Newbies question Peter Bruhn
  1999-10-02 18:04 ` Gerd Stolpmann
  1999-10-03 10:58 ` Markus Mottl
@ 1999-10-04 13:37 ` Xavier Leroy
  2 siblings, 0 replies; 4+ messages in thread
From: Xavier Leroy @ 1999-10-04 13:37 UTC (permalink / raw)
  To: Peter Bruhn, caml-list

> The following function does not compile, since the compiler thinks it has
> the wrong return type: 

You've already received plenty of explanations on what's going on.
Let me just add one easy way to work around this: just have your "try"
construct return () in all cases.  Like this:

>     let read_res file : ('a * 'b) list =
>       let final_result = ref [] in
>       let fd = open_in file in
>       begin 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
>       with             
>         Lexres.Eof ->  ()             (* this is the "normal" loop exit *)
>       | Parsing.Parse_error ->          
>           close_in fd; printf "ERROR: Ressourcen Datei fehlerhaft\n";
>           exit (-1)
>       end;
>       close_in fd; !final_result

- Xavier Leroy




^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~1999-10-04 17:57 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
1999-10-01 13:01 Newbies question Peter Bruhn
1999-10-02 18:04 ` Gerd Stolpmann
1999-10-03 10:58 ` Markus Mottl
1999-10-04 13:37 ` Xavier Leroy

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).