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

Scheme Discussion :

Erreur de fin de programme


Sujet :

Scheme

  1. #1
    Membre à l'essai
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    22
    Détails du profil
    Informations personnelles :
    Âge : 44
    Localisation : France, Nord (Nord Pas de Calais)

    Informations forums :
    Inscription : Juin 2008
    Messages : 22
    Points : 24
    Points
    24
    Par défaut Erreur de fin de programme
    Bonjour !
    Je viens de me mettre au scheme (j'ai juste quelques heure derrière moi) et je tombe sur un type d'erreur que je ne comprend pas :

    Citation Envoyé par DrScheme
    procedure application: expected procedure, given: (void); arguments were: (void)
    Le but de ce programme est un petit jeu : il génère un nombre entre 0 et 99, puis demande à l'utilisateur de le trouver par saisies successives (de nombres). Si le nombre est trouvé, le programme affiche en combien de coup, sinon il indique si le nombre et plus grand ou plus petit.

    En voici une sortie :
    Citation Envoyé par DrScheme
    > (jeu)
    50
    trop grand !
    25
    trop petit
    35
    trop petit
    45
    trop grand !
    40
    trop petit
    43
    trop grand !
    42
    victoire en 7 coup !
    procedure application: expected procedure, given: (void); arguments were: (void)
    J'ai fait une fonction "readNumber" qui va demander la saisie jusqu'à obtenir un numérique (pas de problème à ce niveau) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    (define (readNumber)
      (let ((n (read)))
        (if (number? n) n (readNumber))))
    Ensuite j'ai fait ma "fonction principale" jeu.
    Elle contient une fonction récursive interne "coup" (d'où vient le bug) qui prend en paramètres le numéro du coup et le nombre à trouver.
    On demande un nombre via "readNumber", si c'est le bon nombre on affiche le message de victoire, sinon on affiche soit "plus grand", soit "plus petit" et on rappelle récursivement "coup" en augmentant le numéro de coup de 1.

    Le reste du programme ne fait que générer un nombre et lancer le premier appel de coup...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    (define (jeu)
      (define (coup n nb)
        (let ((saisie (readNumber)))
          (if (= saisie nb)
            ((display (string-append "victoire en " (number->string n 10) " coup !")) (newline)) 
            ((if (> saisie nb) (display "trop grand !") (display "trop petit")) (newline) (coup (+ n 1) nb)) )))
      (let ((nb (random 100))) (coup 1 nb)))
    Voilà. J'ai l'impression que ça viens du fait que je met plusieurs fonctions dans les expressions du si :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    (if (test) (fonction) (fonction))
    ne pose pas de problème
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    (if (test) ((fonction)(fonction)) ((fonction)(fonction)))
    génère cette erreur...
    Si quelqu'un peut éclairer ma lanterne...

    Et tant qu'à faire autant le demander () : mon code est t-il "bien pensé" ?
    personnellement je ne suis pas très satisfé de la fonction "coup" à cause du compteur de coup passé en paramètres... Mais c'est peut être une condition du paradigme... En tout cas çà m'a pas l'air très optimal d'un point de vue "gestion de la mémoire".

  2. #2
    Expert éminent
    Avatar de Jedai
    Homme Profil pro
    Enseignant
    Inscrit en
    Avril 2003
    Messages
    6 245
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Avril 2003
    Messages : 6 245
    Points : 8 586
    Points
    8 586
    Par défaut
    Pour faire une séquence de commande, il faut utiliser begin :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    {begin
      (display 10)
      (newline)}
    (Varie un peu tes parenthèses avec des crochets et des accolades, ça renforce la lisibilité).

    --
    Jedaï

  3. #3
    Membre régulier Avatar de +Guilhem
    Profil pro
    Ingénieur d'études Java/JEE
    Inscrit en
    Novembre 2007
    Messages
    78
    Détails du profil
    Informations personnelles :
    Âge : 35
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur d'études Java/JEE

    Informations forums :
    Inscription : Novembre 2007
    Messages : 78
    Points : 112
    Points
    112
    Par défaut
    En effet, le problème vient bien du if.

    Quand tu écris :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    (if (test) ((fonction1) (fonction2)) ((fonction3) (fonction4)))
    Cela veut dire que, si test est vérifié, la fonction (fonction1) est appelée avec l'argument (fonction2). C'est le principe du langage.

    Si tu veux évaluer plusieurs expressions dans un if, et donc pour palier à ton problème, il existe la "fonction" begin :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    (begin expr1
           expr2
           ...
           exprN)
    Begin évalue toutes les expressions séquentiellement et retourne le dernier résultat (exprN).

    Tu peux donc l'utiliser comme ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    (if (test) (begin (fonction1) (fonction2)) (begin (fonction3) (fonction4)))
    Begin est uniquement utile dans ce cas de figure, quand on veut évaluer plusieurs expressions à la suite dans un if, pour éviter les ambigüités avec le "else" du if.


    Mais mieux que cette solution (à mon avis), c'est d'utiliser cond à la place de if, car tu as un nouveau if à l'intérieur du "else" du if principal :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    (cond ((= saisie nb) ...)
          ((< saisie nb) ...)
          ((> saisie nb) ...))
    C'est plus propre et tu peux séquencer autant d'expressions après chaque condition.


    Voila, je sais pas si je suis très clair, sinon Garulfo ou d'autres se feront un plaisir de t'expliquer je pense.
    EDIT : Grilled !


    P.S. : " En tout cas çà m'a pas l'air très optimal d'un point de vue "gestion de la mémoir" ". Pourquoi donc ? C'est une récursivité terminale donc ça m'a l'air pas trop mal.

  4. #4
    Membre à l'essai
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    22
    Détails du profil
    Informations personnelles :
    Âge : 44
    Localisation : France, Nord (Nord Pas de Calais)

    Informations forums :
    Inscription : Juin 2008
    Messages : 22
    Points : 24
    Points
    24
    Par défaut
    Ok ok ok...
    Merci à vous pour les explications et conseils !

    Du coup j'interprète mieux le message d'erreur du compilateur "procedure application: expected procedure, given: (void); arguments were: (void)"
    comme "mauvaise utilisation d'une fonction, à laquelle je donne un argument de type void alors qu'elle n'en attend aucun."

    Pour ce qui est de la gestion de la mémoire, j'ai peut être un regard naïf sur la chose mais voilà comment je vois les choses avec mes (très petites) notions de compilation et assembleur :

    Dans la fonction scheme suivante :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    {define (coup n nb)
      {let ((saisie (read)))
        {cond
          {[= saisie nb] (display (string-append "victoire en " (number->string n 10) " coup !")) (newline)}
          {else
            (if [> saisie nb] (display "trop grand !") (display "trop petit"))
            (newline)
            (coup (+ n 1) nb)}}}}
    qu'on appellerait par exemple de cette manière :
    Imaginons que l'on trouve la solution en 5 coups.
    On à donc 5 appelles de ma fonction coup, avec ce que çà implique comme gestion de la pile et tout çà;
    Et comme les fonctions sont imbriquées les une dans les autres, les cinq fonctions se terminent toutes les 5 ensembles, du coup on culmine avec 3*5=15 variables en mémoire (dont 10 d'arguments, dont 5 ayant strictement la même valeur et la même utilité) + les variables de retour de fonctions dont je dirait 1 variable créer pour 3 détruites, donc au pire on culmineras avec 16 variables, et dans le cas d'un ramasse-miette 20. (je ne prend pas en compte les test des conditionnelles pour simplifier et les variables provoqué par le (+ n 1))


    Dans un code itératif, par exemple en C-like, je produirait le code suivant :
    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
    17
    18
    19
    20
    void main(int argc, char* argv)
    {
    	int compteur = 0**;
    	int saisie = O*;
    	int nb = random(100)*;
    	
    	do {
    		compteur += 1*;
    		saisie = read()*;
    		if(saisie *!= nb)
    		{
    			if(saisie > nb)*;
    				printf(’trop grand *!\n’)*;
    			else
    				printf(’trop petit *!\n’)*;
    		}
    	} until (saisie = nb)*;
    	printf(’victoire en % coup *!’, nb)*;
    }
    Je ne prend pas nom plus en compte les conditionnelles et le 'compteur += 1'...
    Avec ce code, on à donc 1 appel de ma fonction et 3 variables créer, quel que soit le nombre d'itération...

  5. #5
    Inactif  
    Profil pro
    Inscrit en
    Juillet 2005
    Messages
    1 958
    Détails du profil
    Informations personnelles :
    Âge : 58
    Localisation : France

    Informations forums :
    Inscription : Juillet 2005
    Messages : 1 958
    Points : 2 467
    Points
    2 467
    Par défaut
    Je vais juste répondre à ça. Peut-être plus tard, répondrais-je au reste.

    Citation Envoyé par Sygénème Voir le message
    Du coup j'interprète mieux le message d'erreur du compilateur "procedure application: expected procedure, given: (void); arguments were: (void)"
    comme "mauvaise utilisation d'une fonction, à laquelle je donne un argument de type void alors qu'elle n'en attend aucun."[...]
    La bonne interprétation serait plutôt:
    « mauvaise utilisation de l'appel d'une fonction, c'est-à-dire d'une expression de la forme (a_0 a_1 ... a_n)a_0 devrait-être une fonction et où tu as mis quelque chose qui a renvoyé (void). »
    C'est, en effet, ce que fait un display.
    Attention à ne pas confondre « fonction » et « appel de fonction ».

  6. #6
    Expert éminent
    Avatar de Jedai
    Homme Profil pro
    Enseignant
    Inscrit en
    Avril 2003
    Messages
    6 245
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Avril 2003
    Messages : 6 245
    Points : 8 586
    Points
    8 586
    Par défaut
    Citation Envoyé par Sygénème Voir le message
    Imaginons que l'on trouve la solution en 5 coups.
    On à donc 5 appelles de ma fonction coup, avec ce que çà implique comme gestion de la pile et tout çà;
    Et comme les fonctions sont imbriquées les une dans les autres, les cinq fonctions se terminent toutes les 5 ensembles, du coup on culmine avec 3*5=15 variables en mémoire (dont 10 d'arguments, dont 5 ayant strictement la même valeur et la même utilité) + les variables de retour de fonctions dont je dirait 1 variable créer pour 3 détruites, donc au pire on culmineras avec 16 variables, et dans le cas d'un ramasse-miette 20. (je ne prend pas en compte les test des conditionnelles pour simplifier et les variables provoqué par le (+ n 1))
    Non, les 5 appels ne sont pas imbriqués, parce que la récursion est terminale, c'est à dire que coup est rappelé à la toute fin de coup, et son résultat est directement renvoyé. De ce fait, le compilateur/interpréteur Scheme n'empile pas l'appel récursif mais remplace simplement l'appel précédent de coup par le nouveau (en réutilisant éventuellement une part de la structure), au final le code généré ressemble beaucoup à ce qu'un compilateur produirait à partir de ta boucle en C.

    La récursivité terminale est l'une des optimisations les plus importantes pour les langages fonctionnels où la récursion est un instrument de choix. Attention, toutes les récursivités ne sont pas terminales (cependant toute boucle itérative en C peut être traduite directement par une récursion terminale, il y a une équivalence entre les deux).

    --
    Jedaï

  7. #7
    Membre à l'essai
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    22
    Détails du profil
    Informations personnelles :
    Âge : 44
    Localisation : France, Nord (Nord Pas de Calais)

    Informations forums :
    Inscription : Juin 2008
    Messages : 22
    Points : 24
    Points
    24
    Par défaut
    Citation Envoyé par Garulfo Voir le message
    La bonne interprétation serait plutôt:
    « mauvaise utilisation de l'appel d'une fonction, c'est-à-dire d'une expression de la forme (a_0 a_1 ... a_n)a_0 devrait-être une fonction et où tu as mis quelque chose qui a renvoyé (void). »
    En effet. Du coup çà déplace ce que je pensait être "l'argument" problématique.

  8. #8
    Membre à l'essai
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    22
    Détails du profil
    Informations personnelles :
    Âge : 44
    Localisation : France, Nord (Nord Pas de Calais)

    Informations forums :
    Inscription : Juin 2008
    Messages : 22
    Points : 24
    Points
    24
    Par défaut
    Citation Envoyé par Jedai Voir le message
    Non, les 5 appels ne sont pas imbriqués, parce que la récursion est terminale (...) au final le code généré ressemble beaucoup à ce qu'un compilateur produirait à partir de ta boucle en C
    D'accord, je me suis un peu plus attardé sur la récursion terminale aujourd'hui, et effectivement çà devient une optimisation essentielle... J'avais un peu de mal à accepter que çà fonctionne mais sachant maintenant que le code généré ressemble beaucoup à ce qu'un compilateur produirait à partir de ta boucle en C je comprend cette optimisation...

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Message d'erreur "Fin du programme Member Window"
    Par Ouiwe dans le forum Windows XP
    Réponses: 2
    Dernier message: 13/12/2010, 20h24
  2. Erreur bizarre APRES la fin du programme
    Par Papy214 dans le forum C#
    Réponses: 14
    Dernier message: 17/03/2009, 11h37
  3. erreur à la fin du programme
    Par adel25 dans le forum SL & STL
    Réponses: 2
    Dernier message: 22/02/2009, 11h50
  4. Erreur à la fin d'un programme.
    Par Rappunzell dans le forum C
    Réponses: 2
    Dernier message: 06/12/2007, 07h22
  5. Désactiver les messages d'erreur de Fin de programme
    Par spynux dans le forum Windows XP
    Réponses: 4
    Dernier message: 12/09/2007, 21h03

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