Mantis Bug Tracker

View Issue Details Jump to Notes ] Issue History ] Print ]
IDProjectCategoryView StatusDate SubmittedLast Update
0001231OCamlOCaml generalpublic2002-07-10 16:002014-05-30 11:24
Reporteradministrator 
Assigned Toshinwell 
PrioritynormalSeverityfeatureReproducibilityalways
StatusresolvedResolutionfixed 
PlatformOSOS Version
Product Version 
Target VersionFixed in Version4.02.0+beta1 / +rc1 
Summary0001231: Feature wish: better pretty-printing for cyclic values
DescriptionHello,

l'affichage d'une valeur circulaire (créée avec un let rec ou avec
des effets de bords) dans le toplevel n'est pas très satisfaisante:
il ne termine que parce que le pretty-printer s'arrête à une certaine
profondeur.

On peut imaginer de detecter les boucles comme pour les types récursifs
et de les briser en introduisant des alias, par exemple:

type t = { x : int; mutable y : t option };;
let a = { x = 10; y = None };;
a.y <- Some a;;
a;;


donnerait:

{ x = 10; y = Some #a } as #a

ou peut-être:

#a where #a = { x = 10; y = Some #a}

(ou n'importe quelle autre syntaxe pour les «variables de valeurs»).

La deuxième possibilité permet parfois d'y voir plus clair
lorsqu'il y a des boucles imbriquées, si on autorise la forme
plus générale: v where #a1 = v1 and ... and #an = vn.
Par exemple, pour let rec x = 1 :: y and y = 2 :: x in (x,y) :

(#a, #b) where #a = 1 :: #b and #b = 2 :: #a

(pour les listes, il faudrait renoncer aux crochets, et utiliser
explicitement le constructeur (::))


Un affichage soigné des valeurs cycliques serait très appréciable lorsque
l'on fait dans le toplevel la mise au point d'algorithmes sur des graphes.
Je ne vois pas vraiment de difficultés techniques. Est-ce que vous
envisagez d'implémenter ce genre de chose ?


-- Alain

TagsNo tags attached.
Attached Files

- Relationships
has duplicate 0006228resolvedshinwell Toplevel printer does not detect cycles 

-  Notes
(0000131)
administrator (administrator)
2002-07-10 17:41

> On peut imaginer de detecter les boucles comme pour les types récursifs
> et de les briser en introduisant des alias, par exemple:
[...]
> type t = { x : int; mutable y : t option };;
> let a = { x = 10; y = None };;
> a.y <- Some a;;
> a;;
>
>
> donnerait:
>
> { x = 10; y = Some #a } as #a
>
> ou peut-être:
>
> #a where #a = { x = 10; y = Some #a}
>
> (ou n'importe quelle autre syntaxe pour les «variables de valeurs»).
>
> La deuxième possibilité permet parfois d'y voir plus clair
> lorsqu'il y a des boucles imbriquées, si on autorise la forme
> plus générale: v where #a1 = v1 and ... and #an = vn.
> Par exemple, pour let rec x = 1 :: y and y = 2 :: x in (x,y) :
>
> (#a, #b) where #a = 1 :: #b and #b = 2 :: #a
>
> (pour les listes, il faudrait renoncer aux crochets, et utiliser
> explicitement le constructeur (::))
>
>
> Un affichage soigné des valeurs cycliques serait très appréciable lorsque
> l'on fait dans le toplevel la mise au point d'algorithmes sur des graphes.
> Je ne vois pas vraiment de difficultés techniques. Est-ce que vous
> envisagez d'implémenter ce genre de chose ?

Le coût de détection des cycles n'est évidemment pas nul, même s'il
est supportable en pratique.

D'habitude (dans les anciennes implémentations de Caml qui avaient ce
trait), on écrivait

t0 where t0 = ... and t1 = ...

où t était le nom du type concerné. On pourrait maintenant plutôt
écrire

let rec t0 = ... and t1 = ... in
t0

Qui aurait aussi l'avantage d'être un programme Caml légal...

Pierre Weis

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


(0000132)
administrator (administrator)
2002-07-10 19:19

On Wed, 10 Jul 2002, Pierre Weis wrote:

> Le coût de détection des cycles n'est évidemment pas nul, même s'il
> est supportable en pratique.

Oui ! Mais de toute manière, il y a une limite à la taille de la
valeur affichée, donc le surcout est une constante.

> D'habitude (dans les anciennes implémentations de Caml qui avaient ce
> trait), on écrivait
>
> t0 where t0 = ... and t1 = ...

Ah tiens, pourquoi ça a changé ? J'ai justement choisi cette notation
pour mon language CDuce; les types récursifs me semblent beaucoup plus
lisibles ainsi.

> où t était le nom du type concerné. On pourrait maintenant plutôt
> écrire
>
> let rec t0 = ... and t1 = ... in
> t0
>
> Qui aurait aussi l'avantage d'être un programme Caml légal...


Comme une demande a toujours plus de poids quand on envoie du code avec,
voici un patch par rapport à la version CVS:

Index: toplevel/genprintval.ml
===================================================================
RCS file: /caml/ocaml/toplevel/genprintval.ml,v
retrieving revision 1.31
diff -r1.31 genprintval.ml
176c176,199
< let rec tree_of_val depth obj ty =
---
> let counter = ref 0 in
> let named = ref [] in
> let new_name result =
> incr counter;
> let name = "v" ^ string_of_int !counter in
> named := (name,result) :: !named;
> name in
>
> let rec tree_of_val visited depth obj ty =
> try
> let (alias,result) = List.assq obj visited in
> let name = match !alias with
> | Some x -> x
> | None ->
> let x = new_name result in
> alias := Some x;
> x
> in
> Oval_stuff name
> with Not_found ->
> begin
> let myname = ref None in
> let mytree = ref None in
> let visited = (obj, (myname,mytree)) :: visited in
182a206
> let result =
189c213
< Oval_tuple (tree_of_val_list 0 depth obj ty_list)
---
> Oval_tuple (tree_of_val_list 0 visited depth obj ty_list)
191c215
< tree_of_exception depth obj
---
> tree_of_exception visited depth obj
203c227
< tree_of_val (depth - 1) (O.field obj 0) ty_arg in
---
> tree_of_val visited (depth - 1) (O.field obj 0) ty_arg in
223c247
< tree_of_val (depth - 1) (O.field obj i) ty_arg in
---
> tree_of_val visited (depth - 1) (O.field obj i) ty_arg in
233c257
< then let v = tree_of_val depth (Lazy.force (O.obj obj)) ty_arg in
---
> then let v = tree_of_val visited depth (Lazy.force (O.obj obj)) ty_arg in
243c267
< tree_of_val depth obj
---
> tree_of_val visited depth obj
260c284
< constr_name 0 depth obj ty_args
---
> constr_name 0 visited depth obj ty_args
276c300
< tree_of_val (depth - 1) (O.field obj pos)
---
> tree_of_val visited (depth - 1) (O.field obj pos)
298c322
< tree_of_val (depth - 1) (O.field obj 1) ty in
---
> tree_of_val visited (depth - 1) (O.field obj 1) ty in
316c340
< tree_of_val (depth - 1) obj ty
---
> tree_of_val visited (depth - 1) obj ty
320c344
< tree_of_val (depth - 1) obj ty
---
> tree_of_val visited (depth - 1) obj ty
322a347,350
> in
> match !myname with
> | Some x -> mytree := Some result; Oval_stuff x
> | None -> result
323a352
> end
325c354
< and tree_of_val_list start depth obj ty_list =
---
> and tree_of_val_list start visited depth obj ty_list =
329c358
< let tree = tree_of_val (depth - 1) (O.field obj i) ty in
---
> let tree = tree_of_val visited (depth - 1) (O.field obj i) ty in
334c363
< tree_of_cstr cstr_name start depth obj ty_args =
---
> tree_of_cstr cstr_name start visited depth obj ty_args =
336c365
< let args = tree_of_val_list start depth obj ty_args in
---
> let args = tree_of_val_list start visited depth obj ty_args in
339c368
< and tree_of_exception depth bucket =
---
> and tree_of_exception visited depth bucket =
355c384
< (fun x -> Oide_ident x) name 1 depth bucket cstr.cstr_args
---
> (fun x -> Oide_ident x) name 1 visited depth bucket cstr.cstr_args
361c390,398
< in tree_of_val max_depth obj ty
---
> in
> let result = tree_of_val [] max_depth obj ty in
> let named =
> List.rev_map
> (function (x,{contents=Some y}) -> (x,y)
> | _ -> assert false)
> !named in
> Oval_aliases (result, named)
>
Index: typing/oprint.ml
===================================================================
RCS file: /caml/ocaml/typing/oprint.ml,v
retrieving revision 1.7
diff -r1.7 oprint.ml
52a53,57
> | Oval_aliases (v, b) ->
> if b = []
> then print_simple_tree ppf v
> else fprintf ppf "@[<1>let rec@ %a@ in@ %a@]" print_aliases b
> print_tree_1 v
53a59,65
> and print_aliases ppf = function
> | [ (name,alias) ] ->
> fprintf ppf "@[<1>%s@ =@ %a@]" name print_tree_1 alias
> | (name,alias) :: r ->
> fprintf ppf "@[<1>%s@ =@ %a@ and@ %a@]" name print_tree_1
> alias print_aliases r
> | [] -> assert false
Index: typing/outcometree.mli
===================================================================
RCS file: /caml/ocaml/typing/outcometree.mli,v
retrieving revision 1.7
diff -r1.7 outcometree.mli
42a43
> | Oval_aliases of out_value * (string * out_value) list



Notes:
- les alias sont tous introduits au niveau supérieur
- les chaines de formattage pourraient être mieux écrites
- pas de traitement particulier pour les listes (il en faudrait)
- ça ne met en évidence que les égalités physiques entre une valeur
  et celles qui sont accessibles à partir de celle-ci, donc:

# let rec x = (x,y) and y = (y,x) in (x,y);;
- : ('a * ('b * 'a as 'b) as 'a) * ('c * ('d * 'c as 'd) as 'c) =
let rec v1 = (v1, v2) and v2 = (v2, v1) and v3 = (v3, v4) and v4 = (v4, v3)
 in (v1, v3)

  Pour voir toutes les égalités (est-ce souhaitable ?), il faut
  changer un peu plus la structure du code de Genprintval



-- Alain

(0011584)
shinwell (developer)
2014-05-30 11:24

I think the fix to 6228 resolves this.

- Issue History
Date Modified Username Field Change
2005-11-18 10:13 administrator New Issue
2014-02-08 13:13 yallop Relationship added has duplicate 0006228
2014-05-30 11:24 shinwell Note Added: 0011584
2014-05-30 11:24 shinwell Status acknowledged => resolved
2014-05-30 11:24 shinwell Fixed in Version => 4.02.0+beta1 / +rc1
2014-05-30 11:24 shinwell Resolution open => fixed
2014-05-30 11:24 shinwell Assigned To => shinwell


Copyright © 2000 - 2011 MantisBT Group
Powered by Mantis Bugtracker