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 :

Contribution : Fonctions utilitaires sur les listes


Sujet :

Caml

  1. #1
    Membre émérite
    Avatar de SpiceGuid
    Homme Profil pro
    Inscrit en
    Juin 2007
    Messages
    1 704
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire (Rhône Alpes)

    Informations forums :
    Inscription : Juin 2007
    Messages : 1 704
    Points : 2 990
    Points
    2 990
    Par défaut Contribution : Fonctions utilitaires sur les listes
    Un autre module qui contient des fonctions sur les listes, sauf mention contraire toutes les fonctions sont récursives terminales.

    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
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    (*
     * Author:  Damien Guichard (aka SpiceGuid)
     * Created: 11 fev 2008
     * Updated: 20 fev 2008
     * License: Creative Commons http://creativecommons.org/licenses/by/3.0/
     *)
     
    module Seq = struct
     
    (* not tail recursive *)
    let fold f init l =
      let rec helper l =
        match l with
        | [] -> init
        | a::l -> f (helper l) a
      in helper l
     
    let rec rev_fold f init l =
      match l with
      | [] -> init
      | a::l -> rev_fold f (f init a) l
     
    (* not tail recursive *)
    let fold2 f init l1 l2 =
      let rec helper l1 l2 =
        match l1 , l2 with
        | [], [] -> Some init
        | a1::l1 , a2::l2 ->
            ( match helper l1 l2 with
            | None   -> None
            | Some h -> Some (f h a1 a2)
            ) 
        | _ , _ -> None
      in helper l1 l2
     
    let rec rev_fold2 f init l1 l2 =
      match l1 , l2 with
      | [] , [] -> Some init
      | a1::l1 , a2::l2 -> rev_fold2 f (f init a1 a2) l1 l2
      | _ , _ -> None
     
    let range a b =
      let rec loop n acc =
        if n = a then a::acc
        else loop (pred n) (n::acc)
      in if a <= b then loop b [] else []
     
    let rec last l =
      match l with
      | []   -> None
      | [a]  -> Some a
      | a::l -> last l
     
    (* not tail recursive *)
    let rec poset l =
      match l with
      | [] -> [[]]
      | a::l ->
          let t = poset l
          in  List.rev_append (List.rev_map (fun x -> a::x) t) t
     
    (* not tail recursive *)
    let mapi f n l =
      let rec helper n l =
        match l with
        | []   -> []
        | h::t -> (f n h)::helper (succ n) t
      in helper n l
     
    let rev_mapi f n l =
      let rec loop n l acc =
        match l with
        | [] -> acc
        | h::t -> loop (succ n) t (f n h::acc)
      in loop n l []
     
    (* not tail recursive *)
    let rev_iter f l =
      let rec helper l =
        match l with
        | [] -> ()
        | a::l -> helper l; f a
      in helper l
     
    let rev_filter p l =
      let rec loop l acc =
        match l with
        | [] -> acc
        | h::t ->
            if p h then loop t (h::acc)
            else loop t acc
      in loop l []
     
    let rev_append_map_filter p f l1 l2 =
      let rec loop l acc =
        match l with
        | [] -> acc
        | h::t ->
            if p h then loop t (f h::acc)
            else loop t acc
      in loop l1 l2
     
    let exists_product p l =
      let rec loop l =
        match l with
        | []   -> false
        | h::t -> (exists (p h) t) or loop t
      in loop l
     
    (* not tail recursive *)
    let filter_product p l1 l2 =
      let rec helper l =
        match l with
        | []  -> []
        | a::l -> rev_append_map_filter (p a) (fun b -> a,b) l2 (helper l) 
      in helper l1
     
    let filter_circular p l =
      let rec loop prev l acc = 
        match l with
        | [] -> acc
        | h::t ->
            if p prev h then loop h t ((prev,h)::acc)
            else loop h t acc
      in match last l with
      | None -> [] 
      | Some a -> loop a l []
     
    let lexicographical (cmp: 'a ->'a->int) l1 l2 =
      let rec loop l1 l2 =
        match l1,l2 with
        | [],[] -> 0
        | [],_ -> -1
        | _,[] ->  1
        | a::t1,b::t2 ->
            let r = cmp a b in
            if r = 0 then loop t1 t2
            else r
      in loop l1 l2
     
    let of_string s =
      let rec loop n acc =
        if n < 0 then acc
        else loop (pred n) (s.[n]::acc)
      in loop (String.length s - 1) []
     
    end;;
    Edit:
    • ajout de rev_iter
    • modification de range selon la proposition de Jedai
    • suppression de quelques rec inutiles
    • power_filter est remplacé par poset

  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
    Citation Envoyé par SpiceGuid Voir le message
    Un petit module qui contient quelque fonctions élémentaires parfois utiles comme paramètre d'une fonctionnelle:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    let always x = true
    let never x = false
    let same x = x
    same est traditionnellement appelé id (pour identity), always et never peuvent être résumé et généralisée par le combinateur k (appelé const en Haskell) :
    (NB : En Haskell, le second argument n'est pas évalué grâce à la paresse)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    let not p x = p x = false
    Ce not masque le not sur les booléens, ce n'est donc probablement pas une bonne idée, d'autant qu'on le récupère avec (<<) : (not << p).

    Et pourquoi donc ( :: ) n'est-il pas utilisable, contrairement à (+)... Et pourquoi ( :: ) est-il le seul constructeur infixe possible en OCaml ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    let fst a b = a
    let snd a b = b
    fst et snd sont des fonctions de Pervasives, peut-être vaudrait-il mieux utiliser first et second ici ? (NB : first = const)

    flip est vraiment très utile.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    let rec range a b =
      let rec loop n acc =
        if n = b then b::acc
        else loop (succ n) (n::acc)
      in loop a []
    range 1 3 produit [3;2;1], je ne suis pas sûr que ce soit très intuitif, [1;2;3] serait sans doute mieux, non :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    let rec range a b =
      let rec loop n acc =
        if n = a then a::acc
        else loop (pred n) (n::acc)
      in if a <= b then loop b [] else []
    (et puis évitons les boucles infinies, ça fait mauvais genre )

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    (* not tail recursive *)
    let power_filter p l =
      let rec helper l =
        match l with
        | [] -> if p [] then [[]] else []
        | a::l ->
          let t = helper l
          in  rev_append_filter p (List.rev_map (fun x -> a::x) t) t
      in helper l
    Un nom un peu trompeur peut-être, par exemple si p refuse [], alors cette fonction renvoie []...

    --
    Jedaï

  3. #3
    Membre émérite
    Avatar de SpiceGuid
    Homme Profil pro
    Inscrit en
    Juin 2007
    Messages
    1 704
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire (Rhône Alpes)

    Informations forums :
    Inscription : Juin 2007
    Messages : 1 704
    Points : 2 990
    Points
    2 990
    Par défaut
    J'ai appliqué certains changements que tu as proposés.

    Et pourquoi donc ( :: ) n'est-il pas utilisable, contrairement à (+)
    Parce que :: est un constructeur, alors que + est un opérateur. En fait je ne me pose pas vraiment ce genre de question, et même si je le faisais ça ne changerait rien, alors je me contente de fournir Fun.cons comme substitut.

    (NB : first = const)
    Bien vu.

    Un nom un peu trompeur peut-être, par exemple si p refuse [], alors cette fonction renvoie []...
    Tu préfèrerais plutôt filter_power alors ?

  4. #4
    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 SpiceGuid Voir le message
    Parce que :: est un constructeur, alors que + est un opérateur. En fait je ne me pose pas vraiment ce genre de question, et même si je le faisais ça ne changerait rien, alors je me contente de fournir Fun.cons comme substitut.
    Je sais bien, ce qui ne m'empêche pas de pester contre les décision arbitraires qui interdisent de définir des constructeurs infixes, et de les utiliser comme des fonctions si on les mets entre parenthèses, comme les opérateurs. Ca ne couterait rien, ne serait pas ambigu et uniformiserait un peu le langage.

    Citation Envoyé par SpiceGuid Voir le message
    Tu préfèrerais plutôt filter_power alors ?
    Ben je trouve que la fonction n'est pas géniale, en fait, elle te donne seulement les parties de la liste dont toutes les queues respectent le prédicat, j'ai du mal à voir l'usage. Ca me semble tellement spécialisé que je ne suis pas convaincu que ça ait sa place dans ta librairie (d'un autre côté, cette section est surtout ici à titre pédagogique, alors pourquoi pas...).

    --
    Jedaï

  5. #5
    Membre émérite
    Avatar de SpiceGuid
    Homme Profil pro
    Inscrit en
    Juin 2007
    Messages
    1 704
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire (Rhône Alpes)

    Informations forums :
    Inscription : Juin 2007
    Messages : 1 704
    Points : 2 990
    Points
    2 990
    Par défaut
    Je viens de la tester, elle est carrément nulle, je ne vois plus ce que j'avais en tête au moment où je l'ai écrite. Du coup je préfère renvoyer l'ensemble des parties (c'est la fonction Seq.poset).

    Edit: ajout des fonctions fold, fold2, rev_fold, rev_fold2.

  6. #6
    LLB
    LLB est déconnecté
    Membre expérimenté
    Inscrit en
    Mars 2002
    Messages
    968
    Détails du profil
    Informations forums :
    Inscription : Mars 2002
    Messages : 968
    Points : 1 412
    Points
    1 412
    Par défaut
    Citation Envoyé par Jedai Voir le message
    Je sais bien, ce qui ne m'empêche pas de pester contre les décision arbitraires qui interdisent de définir des constructeurs infixes, et de les utiliser comme des fonctions si on les mets entre parenthèses, comme les opérateurs. Ca ne couterait rien, ne serait pas ambigu et uniformiserait un peu le langage.
    Tu as sûrement remarqué que la distinction identifiant / constructeur se faisait au niveau du lexer : les premiers commencent par une minuscule, les seconds par une majuscule. Je pense que c'est pour la même raison que :: est traité différemment des autres opérateurs : ce n'est pas un identifiant.

    Sur le fond, je suis d'accord avec toi : cette distinction n'est pas naturelle et je trouve ça un peu dommage. J'aimerais aussi que les constructeurs aient une majuscule par convention, plutôt que par obligation ; qu'un constructeur soit considéré comme une fonction à part entière (et bénéfice de l'application partielle, etc.) ; que l'on puisse utiliser n'importe quel opérateur comme constructeur.

    Au final, ce n'est pas trop grave : on s'en sort assez bien en définissant des fonctions auxiliaires, ou en définissant un opérateur qui appelle un constructeur. Mais c'est vrai, ce n'est pas uniforme/élégant.

  7. #7
    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 LLB Voir le message
    Sur le fond, je suis d'accord avec toi : cette distinction n'est pas naturelle et je trouve ça un peu dommage. J'aimerais aussi que les constructeurs aient une majuscule par convention, plutôt que par obligation ; qu'un constructeur soit considéré comme une fonction à part entière (et bénéfice de l'application partielle, etc.) ; que l'on puisse utiliser n'importe quel opérateur comme constructeur.

    Au final, ce n'est pas trop grave : on s'en sort assez bien en définissant des fonctions auxiliaires, ou en définissant un opérateur qui appelle un constructeur. Mais c'est vrai, ce n'est pas uniforme/élégant.
    La majuscule au début des constructeurs ne me gène pas trop, mais je ne vois aucune raison pour que cela empêche de les utiliser comme des fonctions ! Que l'inverse ne soit pas possible (quoique, active pattern...) est normal, mais pourquoi limiter ainsi l'utilité des constructeurs.

    Par rapport aux constructeurs infixes, je me rends maintenant compte qu'il y a un problème : en OCaml, les constructeurs ne prennent qu'un seul argument (ou 0). Donc :: est vraiment un cas très à part... En Haskell tous les constructeurs doivent commencer par une majuscule, et les constructeurs infixes par un ":", mais en Haskell, l'identité entre fonctions et constructeurs est plus forte, les constructeurs sont véritablement des fonctions (sauf qu'on peut les utiliser dans les patterns).

    --
    Jedaï

  8. #8
    Membre éprouvé
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    832
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2007
    Messages : 832
    Points : 1 104
    Points
    1 104
    Par défaut
    Citation Envoyé par LLB
    Au final, ce n'est pas trop grave : on s'en sort assez bien en définissant des fonctions auxiliaires, ou en définissant un opérateur qui appelle un constructeur. Mais c'est vrai, ce n'est pas uniforme/élégant.
    Bof; les constructeurs et les fonctions ne sont pas définis au même niveau, sémantiquement, et il est donc naturel d'avoir une différence syntaxique. Pour tout dire, en Caml Light la convention "constructeur = majuscule" n'est pas imposée, et je le regrette assez souvent.

    Les constructeurs ne sont pas des fonctions, et les fonctions ne sont pas des constructeurs. L'idée de base c'est que les constructeurs sont des valeurs "constantes" (et non des bindings vers des valeurs), qui permettent de construire des valeurs d'un type, mais aussi, symétriquement, de les détruire par le pattern matching. Une fonction ne peut pas faire de pattern matching (en tout cas dans la théorie simple du pattern matching, et même en général, même si on peut étendre un peu cette notion avec vos Active Pattern que je ne connais pas du tout, ou les Views).
    Et ce n'est pas qu'une "différence de mendiant" : il y a une différence aussi du point de vue théorique. Je ne maîtrise pas du tout ce côté là (Jedai ou un autre pourront sûrement mieux te renseigner) mais les constructeurs servent de "projecteurs" pour les types algébriques, et ils ont une valeur théorique forte parce qu'ils servent d'annotation de typage (en gros, le constructeur permet de savoir le type utilisé, et joue donc un rôle crucial dans l'inférence des types).

    Par ailleurs, si ça te fatigue de déclarer les fonctions d'accès/construction à la main, tu peux utiliser une extension syntaxique qui le fait pour toi. J'en ai codée une moi même il y a quelques temps : pa_ty_constr

    Elle transforme le code
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
      type foo = A | B of int * string with constr
    En le code suivant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     type foo = | A | B of int * string
    let _A = A
    let _B _0 _1 = B (_0, _1)
    (et génère aussi les fonctions d'accès pour les enregistrements, comme en Haskell)
    La génération est optionnelle, si tu mets pas de "with constr" il ne générera pas les identifiants.

    Citation Envoyé par Jedai
    Par rapport aux constructeurs infixes, je me rends maintenant compte qu'il y a un problème : en OCaml, les constructeurs ne prennent qu'un seul argument (ou 0).
    Non.
    En OCaml, les constructeurs peuvent avoir autant d'arguments que nécessaire.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    # type foo = A of unit * unit;;
    type foo = A of unit * unit
    # A();;
    The constructor A expects 2 argument(s), but is here applied to 1 argument(s)
    La croyance qu'un constructeur ne peut avoir qu'un seul argument vient d'une double maladresse au niveau de la syntaxe :
    - le choix de l'opérateur * pour séparer les arguments, que l'on confond avec le * des tuples ("type foo = A of unit * unit" est différent de "type foo = A of (unit * unit)")
    - la syntaxe non curryfiée pour les applications de constructeurs : A((), ()) correspond à A () () en Haskell (en réalité, c'est ambigu, parce que si on définit avec "(unit * unit)", alors ( (), () ) désigne bien le couple).

    Ces deux problèmes syntaxiques sont corrigés par la syntaxe révisée :
    - type foo = A of unit and unit
    - A () ()
    - par ailleurs, en bonus pour les Haskelliens, la syntaxe révisée note "list 'a" au lieu de "'a list"
    La syntaxe révisée apporte aussi quelques inconvénients, mais sur ce point elle améliore pas mal.

    Ceci dit, cette ambiguité n'est que de nature syntaxique, le fond reste le même : les constructeurs en OCaml peuvent avoir une arité quelconque.


    Citation Envoyé par Jedai
    Donc :: est vraiment un cas très à part...
    :: est effectivement à part au niveau syntaxique, et on peut regretter qu'il ne soit pas possible de définir d'autres constructeurs infixes (même si en pratique on s'en place très bien).
    Tu notes cependant qu'on *peut* (même si ce n'est absolument pas conseillé, et probablement pas garanti dans la description du langage) redéfinir ::
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    # type arbre = Feuille | :: of arbre * arbre;;
    type arbre = Feuille | :: of arbre * arbre
    # Feuille :: (Feuille :: Feuille);;
    - : arbre = :: (Feuille, :: (Feuille, Feuille))
    Citation Envoyé par Jedai
    mais en Haskell, l'identité entre fonctions et constructeurs est plus forte, les constructeurs sont véritablement des fonctions (sauf qu'on peut les utiliser dans les patterns).
    De mon point de vue, les constructeurs en Haskell dérivent automatiquement des fonctions de constructions, comme le fait mon extension ty_constr, mais en leur donnant le même nom. Il y a donc toujours séparation, mais selon le contexte tu manipules l'objet "constructeur" (dans les pattern), ou l'objet "fonction" (dans le reste du code). Cette identification était faite en Caml Light, mais elle a été retirée depuis.
    En tout cas, je ne pense pas du tout qu'il y aie "identité entre constructeur et fonctions" en Haskell. Ce sont des choses tout à fait différentes, mais les constructeurs donnent implicitement lieu à des fonctions du même nom (et vivant dans un espace de nom différent).

  9. #9
    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 bluestorm Voir le message
    Non.
    En OCaml, les constructeurs peuvent avoir autant d'arguments que nécessaire.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    # type foo = A of unit * unit;;
    type foo = A of unit * unit
    # A();;
    The constructor A expects 2 argument(s), but is here applied to 1 argument(s)
    La croyance qu'un constructeur ne peut avoir qu'un seul argument vient d'une double maladresse au niveau de la syntaxe :
    ....
    Ceci dit, cette ambiguïté n'est que de nature syntaxique, le fond reste le même : les constructeurs en OCaml peuvent avoir une arité quelconque.
    J'avais noté ce message d'erreur, mais tu admettras que de notre point de vue ça ne change pas grand chose, sauf si on utilise la syntaxe révisée. Par exemple, il n'y a pas de curryfication.


    Citation Envoyé par bluestorm Voir le message
    De mon point de vue, les constructeurs en Haskell dérivent automatiquement des fonctions de constructions, comme le fait mon extension ty_constr, mais en leur donnant le même nom. Il y a donc toujours séparation, mais selon le contexte tu manipules l'objet "constructeur" (dans les pattern), ou l'objet "fonction" (dans le reste du code). Cette identification était faite en Caml Light, mais elle a été retirée depuis.
    En tout cas, je ne pense pas du tout qu'il y aie "identité entre constructeur et fonctions" en Haskell. Ce sont des choses tout à fait différentes, mais les constructeurs donnent implicitement lieu à des fonctions du même nom (et vivant dans un espace de nom différent).
    Je ne vois pas ça comme ça : pour moi les constructeurs sont aussi des fonctions, c'est particulièrement apparent si tu utilises la syntaxe des GADT. Par ailleurs je n'ai pas dit qu'il y avait une identité entre constructeurs et fonctions, j'ai dit qu'entre autres les constructeurs étaient des fonctions, ils sont également autre chose.
    Néanmoins là c'est surtout une question de point de vue, tu peux voir ça comme ça t'arrange...

    D'un autre côté d'un point de vue pratique cette identification est très souvent utile et comme elle ne donne lieu à aucune ambiguïté, ne pose aucun problème de performance et renforce l'homogénéité du langage, je trouve que c'est une "identification" fort utile.

    --
    Jedaï

  10. #10
    Membre averti
    Avatar de Strab
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    338
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France

    Informations forums :
    Inscription : Mai 2004
    Messages : 338
    Points : 330
    Points
    330
    Par défaut
    Est-ce vraiment le bon fil de discussion pour ce débat (intéressant, soit dit en passant) ?

  11. #11
    Membre émérite
    Avatar de SpiceGuid
    Homme Profil pro
    Inscrit en
    Juin 2007
    Messages
    1 704
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire (Rhône Alpes)

    Informations forums :
    Inscription : Juin 2007
    Messages : 1 704
    Points : 2 990
    Points
    2 990
    Par défaut
    pour moi les constructeurs sont aussi des fonctions, c'est particulièrement apparent si tu utilises la syntaxe des GADT.
    Dire que c'est particulièrement apparent avec les GADTs c'est un peu comme dire que l'intérêt serait moindre en OCaml et que finalement on peut vivre sans.

  12. #12
    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 SpiceGuid Voir le message
    Dire que c'est particulièrement apparent avec les GADTs c'est un peu comme dire que l'intérêt serait moindre en OCaml et que finalement on peut vivre sans.
    Non, je parlais de la notation des GADT en Haskell qui est pratiquement celle de fonctions :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    data Empty
    data Full
     
    data MyList a content where
      Null ::  MyList a Empty
      Cons :: a -> MyList a c -> MyList a Full
    Juste pour supporter mon point que les constructeurs sont des fonctions d'un genre particulier dont on peut aussi se servir pour construire des patterns.

    --
    Jedaï

  13. #13
    Membre éprouvé
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    832
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2007
    Messages : 832
    Points : 1 104
    Points
    1 104
    Par défaut
    Oui enfin, j'ai l'impression que le coup du GADT renforce tout autant mon argument du "truc spécial, avec une valeur théorique profonde, et cruciale au niveau de l'inférence de type, pas comme une fonction lambda (sic)".

    Je dois avouer que j'explique extrêmement mal cet argument. Je l'avais concocté en lisant un paper li y a quelques mois, je pourrais aller essayer de le retrouver, mais c'est assez loin.

  14. #14
    Rédacteur

    Avatar de millie
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    7 015
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 7 015
    Points : 9 818
    Points
    9 818
    Par défaut
    Comme la discussion fait un peu de HS par rapport à l'autre, elle a été déplacée dans une nouvelle discussion. Tu pourras reposter la version "propre" dans la discussion "Contribution"

  15. #15
    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 bluestorm Voir le message
    Oui enfin, j'ai l'impression que le coup du GADT renforce tout autant mon argument du "truc spécial, avec une valeur théorique profonde, et cruciale au niveau de l'inférence de type, pas comme une fonction lambda (sic)".
    Je ne vois pas trop pouquoi un constructeur serait spécial au niveau de l'inférence de type... Il apporte le même type de contraintes que tout autre type de fonction.

    Edit: ajout des fonctions fold, fold2, rev_fold, rev_fold2.
    fold est fold_right (ou presque : fold f == fold_right (flip f)) et rev_fold est fold_left.

    --
    Jedaï

  16. #16
    Membre émérite
    Avatar de SpiceGuid
    Homme Profil pro
    Inscrit en
    Juin 2007
    Messages
    1 704
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire (Rhône Alpes)

    Informations forums :
    Inscription : Juin 2007
    Messages : 1 704
    Points : 2 990
    Points
    2 990
    Par défaut
    Ben justement, j'en avais marre que fold_left et fold_right n'aient pas le même type.

  17. #17
    alex_pi
    Invité(e)
    Par défaut
    Citation Envoyé par SpiceGuid Voir le message
    Ben justement, j'en avais marre que fold_left et fold_right n'aient pas le même type.
    Ca permet de reconnaitre qui fait quoi en lisant la signature (qui pour moi est plus claire que le nom)

  18. #18
    Membre éprouvé
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    832
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2007
    Messages : 832
    Points : 1 104
    Points
    1 104
    Par défaut
    J'ai vu une très jolie explication à ce sujet dans un paper il y a pas longtemps (et elle m'a permis d'aller dire aux Haskelliens que leur choix d'ordre d'argument est honteux :p ).

    les fold_* sont des fonctions qui agissent sur des fonctions : elles prennent une loi binaire, et la transforment en une loi qui prend une liste sur un de ses deux arguments :
    fold_right : (a -> b -> b) -> (a list -> b -> b)
    fold_left : (b -> a -> b) -> (b -> a list -> b)

    On a cet ordre des listes alternés dans les deux fold_*, parce qu'elles correspondent à une "listisation" de deux arguments différents de la loi binaire de départ.

  19. #19
    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 bluestorm Voir le message
    J'ai vu une très jolie explication à ce sujet dans un paper il y a pas longtemps (et elle m'a permis d'aller dire aux Haskelliens que leur choix d'ordre d'argument est honteux :p ).

    les fold_* sont des fonctions qui agissent sur des fonctions : elles prennent une loi binaire, et la transforment en une loi qui prend une liste sur un de ses deux arguments :
    fold_right : (a -> b -> b) -> (a list -> b -> b)
    fold_left : (b -> a -> b) -> (b -> a list -> b)

    On a cet ordre des listes alternés dans les deux fold_*, parce qu'elles correspondent à une "listisation" de deux arguments différents de la loi binaire de départ.
    D'un je ne comprends pas "listisation", de deux la signature de la fonction paramètre suffit pour connaître l'ordre d'évaluation du fold, inutile d'intervertir 'a list et 'b derrière, de trois, je préfère nettement l'ordre sous Haskell parce qu'il est nettement plus pratique pour la curryfication de foldr même si ça brise une certaine symétrie des signatures.

    foldr est le dual de foldl :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    foldr f b xs = foldl (flip f) b (reverse xs)
    --
    Jedaï

  20. #20
    Membre éprouvé
    Avatar de InOCamlWeTrust
    Profil pro
    Inscrit en
    Septembre 2006
    Messages
    1 036
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2006
    Messages : 1 036
    Points : 1 284
    Points
    1 284
    Par défaut
    Je suis d'accord avec Jedaï ; ce genre de choses sont toujours mieux faites en Haskell : les priorités des opérateurs, leur signature, etc... C'est un langage qui a été fait pour écrire des codes compacts, à l'inverse de OCaml qui est surtout fait pour être lisible et facile à manier (chose en laquelle Haskell est moins bon).

Discussions similaires

  1. fonctions sur les Listes chainées
    Par rototo1 dans le forum C
    Réponses: 7
    Dernier message: 31/01/2013, 18h47
  2. Réponses: 2
    Dernier message: 22/06/2007, 17h25
  3. Recherche fonction sur les listes
    Par becks dans le forum Général Python
    Réponses: 5
    Dernier message: 05/05/2006, 16h11
  4. Fonction MAX sur les lignes
    Par yostane dans le forum Langage SQL
    Réponses: 7
    Dernier message: 01/04/2006, 21h49
  5. Précisions sur les listes
    Par Virgile59 dans le forum Access
    Réponses: 1
    Dernier message: 07/02/2006, 21h20

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