IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Caml Discussion :

Dépassement de la pile, chargement d'une liste à partir d'un fichier


Sujet :

Caml

  1. #1
    Membre à l'essai
    Profil pro
    Inscrit en
    Novembre 2011
    Messages
    49
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2011
    Messages : 49
    Points : 18
    Points
    18
    Par défaut Dépassement de la pile, chargement d'une liste à partir d'un fichier
    Bonjour, je dois charger un dictionnaire de 300.000 mots, seulement j'explose la pile... Stack overflow during evaluation (looping recursion?).
    J'ai bien vu quelques sujets qui parlent de la récursivité terminale, etc... mais pas de réelle solution.

    Voilà ma fonction :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    let rec lire = function (ii) ->
     
            try
     
              let i = input_line (ii) in
     
                i :: lire (ii)
     
            with End_of_file -> [];;
     
    let charge = function (st) ->
     
            let ii = open_in st in
     
              lire (ii);;
    Quelqu'un a t-il une solution pour que je puisse charger tout mon fichier ?

    Merci

  2. #2
    Rédacteur/Modérateur

    Avatar de gorgonite
    Homme Profil pro
    Ingénieur d'études
    Inscrit en
    Décembre 2005
    Messages
    10 322
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur d'études
    Secteur : Transports

    Informations forums :
    Inscription : Décembre 2005
    Messages : 10 322
    Points : 18 679
    Points
    18 679
    Par défaut
    récursivité terminale...
    Evitez les MP pour les questions techniques... il y a des forums
    Contributions sur DVP : Mes Tutos | Mon Blog

  3. #3
    Membre à l'essai
    Profil pro
    Inscrit en
    Novembre 2011
    Messages
    49
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2011
    Messages : 49
    Points : 18
    Points
    18
    Par défaut
    Oui, sauf que j'ai déjà eu bien du mal à faire cette fonction, j'ai pompé la moitié... J'ai fait 3 séances de caml donc, je suis pas contre un meilleur coup de pouce.

  4. #4
    Membre émérite
    Avatar de prgasp77
    Homme Profil pro
    Ingénieur en systèmes embarqués
    Inscrit en
    Juin 2004
    Messages
    1 306
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Eure (Haute Normandie)

    Informations professionnelles :
    Activité : Ingénieur en systèmes embarqués
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Juin 2004
    Messages : 1 306
    Points : 2 466
    Points
    2 466
    Par défaut
    Pour faire court*, le principe de la récursivité terminale (qui est indépendante de la syntaxe OCaml) est de transmettre aux sous-appels le résultat partiel construit jusque là ; chaque itération (appel de la fonciton récursive) transforme ou complète le résultat partiel, jusqu'à parfaire la condition d'arrêt ; il n'y a plus qu'à retourner le résultat tout prêt.

    Un exemple t'aidera à mieux comprendre. Tu trouveras l'exemple du calcul de la factorielle en rec term un peu partout sur le web ; en voici un autre : la somme de tous les éléments d'une liste (dans un cas réel, préférer l'usage de List.fold_left (+) 0) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    let sum_list_elements l =
       let rec aux acc = function
       | [] -> acc
       | head :: tail -> aux (acc + head) tail
       in
       aux 0 l
    ;;
    val sum_list_elements : int list -> int = <fun>
    # sum_list_elements [0;1;2;3;4;5;6;7;8;9;10] ;;
    - : int = 55
    Explicaitons
    Comme tu le vois, dans sum_list_elements (qui n'est pas récursive, inutile), on crée une fonction auxiliaire qui elle fait le travail ; mais elle demande un argument supplémentaire (on verra après pourquoi) qui est zéro ; plutôt que de donner à l'utilisateur cette fonction à l'usage particulier, on l'encapsule dans une fonction bien plus claire (qui est sum_list_elements et qui prend tout simplement en argument une liste d'entiers).

    La fonction aux prend donc deux arguments. Le second est une liste d'entiers à sommer. Le premier, appelé accumulateur (et ça prend tout son sens ici ) est la somme de tous les éléments de la liste déjà traités.

    Voici ce que fait la fonction aux :
    • si on lui donne une liste d'entiers non vide, elle extrait le premier élément, l'ajoute à l'accumulateur et s'appelle elle-même en fournissant l'accumulateur modifié et la queue de la liste ;
    • si on lui donne une liste vide, elle retourne simplement l'accumulateur, qui contient déjà la somme de tous les entiers traités, soit ceux de la liste.


    Exemple pour aux 0 [1;2;3]
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    aux 0 [1;2;3]
    aux (0+1 → 1) [2;3]
    aux (1+2 → 3) [3]
    aux (3+3 → 6) []
    6
    L'intérêt de la récursivité terminale, maintenant que tu as compris son principe, c'est de permettre à OCaml d'optimiser l'appel de la fonction. Dans un cas de récursivité non terminale, une fois arrivés à la condition d'arrêt, les appels successifs retournent leur résultat à l'appel père ; ce résultat est traité puis remonte au grand-père, à l'arrière grand-père… jusqu'à remonter à l'appel premier. Ainsi, OCaml est obligé de garder une trace de tous les appels et de leurs arguments qui sont empilés en mémoire (je te dis pas la duplication de mémoire que ça implique).
    Avec de la rec term, l'appel père n'a pas besoin de traiter le résultat du fils, car le fils a en main toutes les informations nécessaires (la somme des éléments précédents et la liste des éléments suivant dans notre cas). OCaml peut donc « oublier » les appels parents et libérer la pile.

    J'espère que j'ai été clair, désolé pour le long message, je suis en forme aujourd'hui.

    Edit
    (*) HAHA !
    -- Yankel Scialom

  5. #5
    Membre à l'essai
    Profil pro
    Inscrit en
    Novembre 2011
    Messages
    49
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2011
    Messages : 49
    Points : 18
    Points
    18
    Par défaut
    Salut prgasp77,
    avant tout je te remercie pour ta réponse et le temps que tu as consacré à m'expliquer.

    Effectivement, avant même d'entendre parler de récursivité terminale, j'avais bien eu l'intuition de procéder ainsi, c'est à dire découper la tache en repassant la liste déjà créée à chaque nouvel appel de fonction jusqu'à avoir lu tout le fichier...

    Algorithmiquement parlant, ça ne me pose aucun problème, enfin je vois la chose ainsi :

    Lis mon fichier, après N lignes lues, rappelle la fonction et passe lui en argument la liste déjà crée à laquelle tu ajoutes (: la fonction récursives de lectures, etc... Seulement, c'est la syntaxe ici qui me pose problème, parce qu'il y a des try/with...

    Je vais essayer de modifier ma fonction en prenant ton exemple en modèle. C'est très frustrant car je comprends très simplement la manière dont tu expliques la chose mais quand je jette un oeil au code, ça coule pas du tout comme de l'eau de source à certains endroit... Et quand j'essaye du coup de faire pour lire un fichier, ça complexifie davantage et m'égare... J'essaye...

    edit :
    Après 40 minutes :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    let rec lire file =
            try
            			   let rec aux acc = function
                   | _ -> let mot = input_line (file) in
             			 acc :: aux (mot::acc) file 
             			 in 
             			 aux [] file
             with End_of_file -> [];;
     
    let charge = function (st) ->
            let ii = open_in st in
              lire (ii);;

    # let charge = function (st) ->
    val charge : string -> 'a list list = <fun>
    # let rec lire file =
    val lire : in_channel -> string list list = <fun>


    ça me renvoie une liste de liste... Je n'vois pas quoi faire d'autre... J'ai tenté pleins de choses mais rien ne fonctionne...



    Edit :
    Après 50 minutes :
    J'aurai bien tenté :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    let rec lire file =
            try
            			   let rec aux acc = function
                   | _ -> let mot = input_line (file) in
             			 aux (mot::acc) file 
             			 in 
             			 aux [] file
             with  | End_of_file -> acc;;
    mais je ne peux pas renvoyer acc dans le with... Merci de bien vouloir m'aider encore un peu...

    Edit : Après plus d'une heure :

    C'est impossible... -_- Quelqu'un me donne une solution en itératif, je n'ai pas appris l'itératif avec ocaml et j'aimerai m'en préserver car on nous l'a interdit en cours...

    Après 1h30 :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    let rec lire file =
      try
        let rec aux acc x = function
     
            | _ ->
                if x = 10000 then acc @ lire file
                else
                  let mot = input_line (file) in
                    aux (mot :: acc) (x + 1) file
        in
          aux [] 0 file
      with | End_of_file -> [];;
     
    let charge = function (st) ->
            let ii = open_in st in
              lire (ii);;
    ça marche ^^...

  6. #6
    Rédacteur/Modérateur

    Avatar de gorgonite
    Homme Profil pro
    Ingénieur d'études
    Inscrit en
    Décembre 2005
    Messages
    10 322
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur d'études
    Secteur : Transports

    Informations forums :
    Inscription : Décembre 2005
    Messages : 10 322
    Points : 18 679
    Points
    18 679
    Par défaut
    Tu ne fais pas vraiment de la récursivité terminale, tu te contentes juste "d'en faire un peu"

    Par ailleurs, il faudrait ne pas inverser l'ordre de la liste...


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    let lire file =
      let rec aux acc = 
         try
            let mot = input_line file in
            aux (mot::acc)
         with |End_of_file -> acc
      in
      List.rev (aux [])
    ;;
     
    let charge st =
       let ii = open_in st in
       lire ii
    ;;
     
    List.iter (fun s -> Printf.printf "%s\n" s) (charge "toto.txt");;
    Evitez les MP pour les questions techniques... il y a des forums
    Contributions sur DVP : Mes Tutos | Mon Blog

Discussions similaires

  1. Projet de création d'une liste à partir d'un fichier txt
    Par genius2139 dans le forum VBScript
    Réponses: 64
    Dernier message: 09/02/2012, 19h21
  2. Chargement d'une table à partir d'un fichier texte
    Par Trebor_ dans le forum Débuter
    Réponses: 2
    Dernier message: 21/02/2008, 14h31
  3. probleme chargement d'une liste
    Par gnaoui_9999 dans le forum Struts 1
    Réponses: 2
    Dernier message: 29/01/2008, 10h45
  4. Remplir une liste à partir d'un fichier texte
    Par leroidje dans le forum Langage
    Réponses: 1
    Dernier message: 01/07/2007, 08h41
  5. Chargement D Une Liste
    Par flo64 dans le forum Access
    Réponses: 5
    Dernier message: 07/06/2006, 09h06

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo