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

Langage Perl Discussion :

reduce et fonction


Sujet :

Langage Perl

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Expert confirmé Avatar de Flodelarab
    Homme Profil pro
    Inscrit en
    Septembre 2005
    Messages
    5 293
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente (Poitou Charente)

    Informations forums :
    Inscription : Septembre 2005
    Messages : 5 293
    Par défaut reduce et fonction
    Bonjour

    Partons d'une fonction binaire sur deux références. Fonction qui marche bien. Et renvoie une référence.
    Comment utiliser reduce pour qu'elle prenne une liste de références et renvoie une référence ultime ?

    J'essaie cela sans succès :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    return reduce { fonctionbinairesurdeuxreferences($a,$b) },@maliste;
    En tournant autour, Dumper m'a déjà renvoyé "3" ou "undef". Le premier n'a pas de sens et le second est impossible.

    Il y a un problème autour de la fonction reduce.

  2. #2
    Expert confirmé Avatar de disedorgue
    Homme Profil pro
    Ingénieur intégration
    Inscrit en
    Décembre 2012
    Messages
    4 361
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur intégration
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Décembre 2012
    Messages : 4 361
    Par défaut
    Bonjour,

    Déjà la virgule entre ton bloc et ta liste est en trop, la syntaxe est: reduce { BLOC } @liste.

    Sinon un exemple qui fonctionne:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    $ perl -e 'use List::Util qw(reduce) ;sub func{ ($x,$y)=@_;return $x+$y };$foo = reduce { func($a,$b) } 1..10 ;print $foo'
    55

  3. #3
    Expert confirmé Avatar de Flodelarab
    Homme Profil pro
    Inscrit en
    Septembre 2005
    Messages
    5 293
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente (Poitou Charente)

    Informations forums :
    Inscription : Septembre 2005
    Messages : 5 293
    Par défaut
    Merci pour la réponse.

    À force de comparer et de ne pas voir la différence, j'ai compris que $maliste ne contenait pas ce que je croyais.

    Tout marche, maintenant.

    Mais, quelle est la différence entre ces deux syntaxes ?
    et
    La première faisait hurler "reduce" si je ne mettais pas la virgule. Et ne marchait pas de toute façon.
    La seconde est le comportement attendu.

    Selon moi, la première syntaxe absorbe tous les éléments de @_ dans une liste.
    Alors pourquoi un distinguo ?

  4. #4
    Expert confirmé Avatar de disedorgue
    Homme Profil pro
    Ingénieur intégration
    Inscrit en
    Décembre 2012
    Messages
    4 361
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur intégration
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Décembre 2012
    Messages : 4 361
    Par défaut
    Comme ça, au premiers abords, j'aurai du mal à te répondre, car je ne rencontre pas ton souci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    $ perl -e 'use List::Util qw(reduce) ;use strict; my @xx=1..10;sub func{ my ($x,$y)=@_;return $x+$y };my $foo = reduce { func($a,$b) } @xx ;print $foo,"\n"'
    55
    $ perl -e 'use List::Util qw(reduce) ;use strict; my @xx=1..10;sub func{ my ($x,$y)=@_;return $x+$y };my $foo = reduce { func($a,$b) } (@xx) ;print $foo,"\n"'
    55
    Et cette syntaxe se joue principalement sur les scalaires:

    Exemple ou on dit à perl que l'on se place en mode scalaire:
    Donc ici, $x aura comme valeur le nombre d'élément du tableau @_

    Exemple ou on dit à perl que l'on se place en mode liste:
    Donc ici, $x aura le premier élément du tableau @_

    Un autre exemple:
    ici $x aura le premier élément du tableau @_ et le tableau @y tous les autres éléments de @_

    Par contre, on ne peut pas faire l'inverse:
    ici, @y aura tout les éléments du tableau @_ et $x sera non défini

    Et tout ça, c'est juste sur des listes simples.

  5. #5
    Rédacteur/Modérateur

    Avatar de Lolo78
    Homme Profil pro
    Conseil - Consultant en systèmes d'information
    Inscrit en
    Mai 2012
    Messages
    3 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Conseil - Consultant en systèmes d'information
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mai 2012
    Messages : 3 612
    Billets dans le blog
    1
    Par défaut
    Bonjour,

    en principe, il n'y a à ma connaissance pas de différence entre les deux syntaxes (mais je préfère tout de même celle sans les parenthèses, plus simple).

    Exemple à la ligne de commande, avec ou sans parenthèses:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    $ perl -MData::Dumper -e 'sub out { my @l = @_; print Dumper \@l;} out( 1, 2, 3);'
    $VAR1 = [
              1,
              2,
              3
            ];
     
    $ perl -MData::Dumper -e 'sub out { my (@l) = @_; print Dumper \@l;} out( 1, 2, 3);'
    $VAR1 = [
              1,
              2,
              3
            ];
    Tu dois avoir une différence ailleurs dans ton code.

    Edit: grillé à 2 minutes près par disedorgue ++.

  6. #6
    Rédacteur/Modérateur

    Avatar de Lolo78
    Homme Profil pro
    Conseil - Consultant en systèmes d'information
    Inscrit en
    Mai 2012
    Messages
    3 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Conseil - Consultant en systèmes d'information
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mai 2012
    Messages : 3 612
    Billets dans le blog
    1
    Par défaut
    La preuve qu'il n'y a aucune différence entre my @list = @_; et my (@list) = @_;: le compilateur interprète les deux scripts de la même façon:
    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
     
    $ perl -MO=Deparse -e 'sub out { my (@l) = @_; print @l;} out( 1, 2, 3);'
    sub out {
        my(@l) = @_;
        print @l;
    }
    out 1, 2, 3;
    -e syntax OK
     
     
    $ perl -MO=Deparse -e 'sub out { my @l = @_; print @l;} out( 1, 2, 3);'
    sub out {
        my(@l) = @_;
        print @l;
    }
    out 1, 2, 3;
    -e syntax OK

  7. #7
    Expert confirmé Avatar de Flodelarab
    Homme Profil pro
    Inscrit en
    Septembre 2005
    Messages
    5 293
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente (Poitou Charente)

    Informations forums :
    Inscription : Septembre 2005
    Messages : 5 293
    Par défaut
    Merci à vous.

    J'ai voulu re-salir mon code pour revoir l'erreur, mais je ne l'ai pas retrouvée.
    "3" était à coup sûr la taille de la liste.
    Il est sûr, aussi, que je ne me suis pas trompé de préfixe.

    Bizarre. Mais je mets la discussion en résolu.

  8. #8
    Expert confirmé Avatar de disedorgue
    Homme Profil pro
    Ingénieur intégration
    Inscrit en
    Décembre 2012
    Messages
    4 361
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur intégration
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Décembre 2012
    Messages : 4 361
    Par défaut
    Citation Envoyé par Flodelarab Voir le message
    Il est sûr, aussi, que je ne me suis pas trompé de préfixe.
    Cette phrase en dit long car on n'y a jamais fait allusion

  9. #9
    Membre chevronné Avatar de cmcmc
    Homme Profil pro
    Inscrit en
    Juillet 2013
    Messages
    316
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Juillet 2013
    Messages : 316
    Par défaut
    Citation Envoyé par Flodelarab Voir le message
    J'ai voulu re-salir mon code pour revoir l'erreur, mais je ne l'ai pas retrouvée.
    "3" était à coup sûr la taille de la liste.
    Il est sûr, aussi, que je ne me suis pas trompé de préfixe.

    Bizarre. Mais je mets la discussion en résolu.
    Mais, heuuu, tant que ce n'est pas résolu, ce n'est pas résolu, non ?

    Disedorgue a donné la clé du problème, à savoir la virgule excédentaire dans ton invocation de reduce. Poursuivons un chouia.

    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
    $ perl -E '
      use List::Util qw(reduce);
      use Data::Dump qw(dump);
      sub f_ok { return reduce { $a + $b } @_ }
      sub f_ko { return reduce { $a + $b }, @_ }
      for (q{$x = f_ok(1,10,100)},
           q{$x = f_ko(1,10,100)},
           q{($x) = f_ko(1,10,100)}) {
        print "\"$_\" produit \$x = ";
        eval $_;
        say dump($x);
      }'
    "$x = f_ok(1,10,100)" produit $x = 111
    "$x = f_ko(1,10,100)" produit $x = 3
    "($x) = f_ko(1,10,100)" produit $x = undef
    $
    Sans surprise, l'invocation de f_ok place le résultat correct dans $x.

    La première invocation de f_ko place la longueur de la liste dans $x. Tiens tiens. La seconde place undef dans $x. Tiens tiens derechef. Mais qu'est ce que c'est-il donc qu'il se passe-t-il ?

    La différence est que dans la première, $x = impose l'évaluation de f_ko(1,10,100) en contexte scalaire. Dans la seconde, ($x) = impose cette évaluation en contexte de liste. Et ce contexte va changer la manière dont return reduce { $a + $b }, @_ est évalué.

    En contexte scalaire, l'évaluation de expr1, expr2, ..., exprN va évaluer dans l'ordre les expressions expr1, expr2, ..., exprN , chacune en en contexte scalaire, et retourner le résultat de la dernière :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    $ perl -MData::Dump -E 'sub wa { $ret = (wantarray ? "A" : "S") x $_[0]; say "# wa(@_) -> $ret"; $ret }; $x = do { wa(1), wa(2), wa(3) }; dd $x'
    # wa(1) -> S
    # wa(2) -> SS
    # wa(3) -> SSS
    "SSS"
    $
    En contexte de liste, l'évaluation de expr1, expr2, ..., exprN va évaluer dans l'ordre expr1, expr2, ..., exprN , chacune en contexte de liste, et retourner la liste (aplatie) des résultats de ces évaluations :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    $ perl -MData::Dump -E 'sub wa { $ret = (wantarray ? "A" : "S") x $_[0]; say "# wa(@_) -> $ret"; $ret }; @x = do { wa(1), wa(2), wa(3) }; dd @x'
    # wa(1) -> A
    # wa(2) -> AA
    # wa(3) -> AAA
    ("A", "AA", "AAA")
    $ perl -MData::Dump -E 'sub waa { @ret = (scalar(wantarray ? "A" : "S") x $_[0]) x $_[0]; say "# waa(@_) -> @ret"; @ret}; @x = do { waa(1), waa(2), waa(3) }; dd @x'
    # waa(1) -> A
    # waa(2) -> AA AA
    # waa(3) -> AAA AAA AAA
    ("A", "AA", "AA", "AAA", "AAA", "AAA")
    $
    La forme return reduce { $a + $b }, @_, ou de manière équivalente ici reduce { $a + $b }, @_ est de la forme expr1, expr2expr1 et expr2 sont respectivement reduce { $a + $b } et @_.

    reduce { $a + $b } est une expression tout à fait valide, en fait c'est équivalent à reduce { $a + $b } (), autrement dit on opère une réduction sur une liste vide. Le comportement de reduce est documenté pour ce cas : le résultat est undef.

    @_ quant à elle s'évalue à elle même en contexte de liste, et au nombre d'éléments de @_ en contexte scalaire.

    reduce { $a + $b }, @_ s'évalue donc ultimement à la longueur de @_ en contexte scalaire, et à la liste (undef, @_) en contexte de liste. On peut vérifier ce dernier point :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    $ perl -E '
      use List::Util qw(reduce);
      use Data::Dump qw(dump);
      sub f_ko { reduce { $a + $b }, @_ }
      for (q{@y = f_ko(1, 10, 100)}) {
        print "\"$_\" produit \@y = ";
        eval $_;
        say dump(@y);
      }'
    "@y = f_ko(1, 10, 100)" produit @y = (undef, 1, 10, 100)
    $
    Outre le fait qu'elle impose un contexte de liste à l'évaluation, la partie gauche ($x) = effectue un tranchage du résultat, en ne retenant que la première valeur de la liste retournée, soit undef.

    @Flodelarab : je ne prétends pas que tes tentatives aient suivi exactement le motif ci-dessus mais vu les similarités rencontrées dans les résultats ça ne devait pas en être très loin

    Intéressant problème en tous cas

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

Discussions similaires

  1. Différence entre la fonction map() et reduce() de l'API stream
    Par L'aigle de Carthage dans le forum Débuter avec Java
    Réponses: 1
    Dernier message: 10/12/2017, 21h57
  2. fonction inverse de functools.reduce
    Par Trap D dans le forum Général Python
    Réponses: 8
    Dernier message: 20/10/2014, 22h52
  3. Implémentation des fonctions mathématiques
    Par mat.M dans le forum Mathématiques
    Réponses: 9
    Dernier message: 17/06/2002, 16h19
  4. fonction printf
    Par ydeleage dans le forum C
    Réponses: 7
    Dernier message: 30/05/2002, 11h24
  5. FOnction api specifiant la position de la souris
    Par florent dans le forum C++Builder
    Réponses: 4
    Dernier message: 15/05/2002, 20h07

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