caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
From: Pierre Weis <Pierre.Weis@inria.fr>
To: zimmer@easynet.fr (Pascal Zimmer)
Cc: caml-list@inria.fr
Subject: Re: Instruction return
Date: Mon, 2 Jun 1997 16:15:31 +0200 (MET DST)	[thread overview]
Message-ID: <199706021415.QAA21013@pauillac.inria.fr> (raw)
In-Reply-To: <3390602C.20BB@easynet.fr> from Pascal Zimmer at "May 31, 97 10:30:20 am"

> Serait-il possible d'ajouter une instruction return au langage CAML afin 
> de pouvoir sortir directement d'une boucle, comme c'est le cas en C ? Je 
> pense qu'une telle instruction ameliorerait beaucoup la lisibilite du 
> code.

Oui c'est possible et c,a ne pose aucun proble`me pour le reste du langage.
Il faut seulement se persuader que c'est vraiment ne'cessaire.

> Par exemple, cela permettrait de retourner la valeur d'une fonction au 
> cours d'une boucle for, alors que pour l'instant on doit utiliser une 
> boucle while avec un compteur sous forme de pointeur.
> 
> Ainsi, une fonction classique de recherche d'une valeur x dans un tableau 
> non trie v s'ecrit:
> 
> let rech x v =
>  let n = vect_length v in
>  let i = ref 0 in
>  while !i < n & v.(!i) <> x do i := !i + 1 done;
>  not (!i = n);;
> 
> Avec une instruction return, on pourrait l'ecrire ainsi:
> 
> let rech x v =
>  let n = vect_length v in
>  for i=0 to n-1 do
>   if v.(i) = x then return true
>  done; false;;
> 
> Cette derniere forme sans pointeur pour le compteur i est tout de meme 
> plus claire !

Pour sortir d'une boucle il n'est pas besoin d'une telle instruction:
il suffit d'utiliser le me'canisme d'exceptions du langage; lorsqu'on
veut arre^ter la boucle pre'mature'ment on lance une exception, et
l'on prote`ge la boucle a` l'aide d'un try ... with. Il existe
d'ailleurs une exception spe'cialement pre'de'finie pour ce faire:
l'exception Exit. On e'crit donc d'habitude

let rech x v =
 try
  let n = vect_length v in
  for i=0 to n-1 do
   if v.(i) = x then raise Exit
  done; false
 with Exit -> true;;

Bien su^r cela ne suffit pas pour rendre la valeur d'une fonction au
milieu d'une boucle, sauf a` de'finir une exception spe'cifique a`
chaque fonction, sur le mode`le:

exception Return of bool;;

let rech x v =
 try 
  let n = vect_length v in
  for i=0 to n-1 do
   if v.(i) = x then raise (Return true)
  done; false
 with Return b -> b;;

C'est e'videmment un peu lourd (et ca ne marche pas pour les fonctions
polymorphes). C'est pourquoi on pre'fe`re alors conside'rer que la
boucle est trop complexe pour une boucle for ou while et qu'il est
temps d'utiliser des outils adapte's a` e'crire des boucles
arbitrairement complexes, c'est-a`-dire les fonctions re'cursives.

let rech x v =
 let rec boucle i =
  if i < vect_length v then
    if v.(i) = x then true else trouve (i + 1)
  else false in
 boucle 0;;

ou encore, apre`s un peu de re'e'criture:

let rech x v =
 let rec boucle i = i < vect_length v && (v.(i) = x || boucle (i + 1)) in
 boucle 0;;

Ce qui est encore plus bref (plus simple?) que la boucle for et posse`de
l'immense avantage d'e^tre comple`tement ge'ne'ral et de ne pas
ne'cessiter d'instruction supple'mentaire.

> Bien entendu, le typeur devra verifier que le type renvoye par return est 
> le meme que celui renvoye par la derniere instruction de la fonction.
> Une telle possibilite (renvoi par return ou par la derniere instruction) 
> est par exemple utilisee par le langage de programmation de MAPLE, sauf 
> qu'il n'y a aucun controle de type.

Il suffit pour cela de typer le corps d'une fonction en e'tendant
l'environnement avec une liaison pour l'identificateur return de type
'a -> 'a; on doit enfin unifier 'a avec le type obtenu pour le corps
de la fonction. La compilation correspond en gros a` ge'ne'rer un
goto. Il n'y a donc pas de re'elle difficulte'.

> J'aimerais donc savoir si une telle instruction est possible ou s'il y a 
> incompatibilite avec le reste du langage.

C'est donc possible, et ce n'est pas incompatible, mais est-ce ne'cessaire ?

De surcroi^t, il n'est pas certain que cette construction facilite
vraiment la lecture, dans la mesure ou` la valeur de retour des
fonctions serait alors bien moins facile a` localiser, puisque qu'elle
pourrait apparai^tre n'importe ou` dans le corps de la fonction.

(conside'rez me^me un programme sans boucles:

 let f x =
  let y = if ... then return 1 else 2 in
  if y > x then x + 1 else y;;
 
(dans certains cas) la valeur de retour de f est obtenue (et rendue)
pendant l'e'valuation de l'expression de'finissant y ...)

Cela dit l'argument est faible, car il est toujours facile d'e'crire
des programmes illisibles, me^me avec les meilleures constructions
possibles dans le langage (comme en Caml :).

Peut-e^tre avez-vous des exemples encore plus convaincants ?

> [English: Is it possible to add a 'return' instruction to the CAML 
> language, like in C ?]

Yes it is possible, but is it necessary ?

To escape from loops, use the predefined exception Exit, and enclose
the loop inside a try with:

let rech x v =
 try
  let n = vect_length v in
  for i=0 to n-1 do
   if v.(i) = x then raise Exit
  done; false
 with Exit -> true;;

To return the result of a function from inside a loop, it's a bit more
tricky: you must define first an exception that could carry the result (in
your case a boolean):

exception Return of bool;;

Then you enclose the body of the function within a try with construct:

let rech x v =
 try 
  let n = vect_length v in
  for i=0 to n-1 do
   if v.(i) = x then raise (Return true)
  done; false
 with Return b -> b;;

In fact the best way of writing complex loops is via recursive
function definitions:

let rech x v =
 let rec boucle i = i < vect_length v && (v.(i) = x || boucle (i + 1)) in
 boucle 0;;

This is even shorter than the version with the return construct, and
uses a more general concept that the return construct.

Last, the addition of the return construct could be considered
harmful, since the returned value of functions could now be easily
hidden anywhere in the body of the function.

(consider the following program:

 let f x =
  let y = if ... then return 1 else 2 in
  if y > x then x + 1 else y;;
 
the returned value of f is computed and returned during the evaluation
of the expression that defines y...)

However this is poor, since it is easy to write bad programs, even if
you have the best constructs in the language (as in Caml :)

Have you other examples that could convince us to adopt the return
construct ?

Pierre Weis

INRIA, Projet Cristal, Pierre.Weis@inria.fr, http://pauillac.inria.fr/~weis/





  reply	other threads:[~1997-06-02 14:51 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
1997-05-31 17:30 Pascal Zimmer
1997-06-02 14:15 ` Pierre Weis [this message]
1997-06-03  8:37   ` Vincent Poirriez
1997-06-03 10:24     ` Pierre Weis
1997-06-03 14:17       ` Vincent Poirriez
1997-06-02 16:23 Dwight VandenBerghe
1997-06-02 21:41 ` Pierre Weis

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=199706021415.QAA21013@pauillac.inria.fr \
    --to=pierre.weis@inria.fr \
    --cc=caml-list@inria.fr \
    --cc=zimmer@easynet.fr \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).