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 :

[OCaml & F#] Priorité des opérateurs


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 991
    Points
    2 991
    Par défaut [OCaml & F#] Priorité des opérateurs
    Dans son chapitre L05 Laurent Le Brun présente 4 opérateurs standards en F# :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    let (<<) g f x = g (f x)
    and (>>) f g x = g (f x)
    and (|>) x f = f x
    and (<|) f x = f x
    ;;
    Puis-je utiliser ces mêmes définitions en OCaml sans compromettre la portabilité vers F#, la priorité respective de ces 4 opérateurs est-elle exactement identique dans les deux langages ?

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

    Informations forums :
    Inscription : Juillet 2005
    Messages : 1 958
    Points : 2 467
    Points
    2 467
    Par défaut
    Citation Envoyé par SpiceGuid Voir le message
    Dans son chapitre L05 Laurent Le Brun présente 4 opérateurs standards en F# :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    let (<<) g f x = g (f x)
    and (>>) f g x = g (f x)
    and (|>) x f = f x
    and (<|) f x = f x
    ;;
    Puis-je utiliser ces mêmes définitions en OCaml sans compromettre la portabilité vers F#, la priorité respective de ces 4 opérateurs est-elle exactement identique dans les deux langages ?
    C'est quoi dans F# ?
    Je trouve que c'est un mauvais choix >> et << pour la composition. Était-ce un exemple de cours ?
    C'est ce genre de choix qui fait qu'il y des détracteurs de la surcharge d'opérateurs en C++ par exemple. Il faut essayer de garder un sens « classique » au symbole. Maintenant, il faut reconnaître que << et <| n'est pas vraiment de sens classique.

  3. #3
    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
    Il me semble que les règles de priorité sont assez proches. Je ne peux pas garantir, mais je pense que c'est compatible. Je viens de tester le code suivant, Caml l'accepte sans problème :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    [1; 2; 3; 4] |> List.map succ
                   |> List.map (( * ) 2)
                   |> List.iter (Printf.printf "%d")
    J'ai fait quelques autres tests, ça me semble avoir le même comportement.

    Je trouve que c'est un mauvais choix >> et << pour la composition. Était-ce un exemple de cours ?
    Non, c'est défini dans la bibliothèque standard de F#. Ces opérateurs sont régulièrement utilisés, et je trouve ça dommage que Caml ne les ait pas par défaut.

    C'est ce genre de choix qui fait qu'il y des détracteurs de la surcharge d'opérateurs en C++ par exemple. Il faut essayer de garder un sens « classique » au symbole. Maintenant, il faut reconnaître que << et <| n'est pas vraiment de sens classique.
    Ce n'est pas de la surcharge d'opérateurs ici : << et >> n'ont qu'un seul sens (contrairement à C++). En Caml, ces opérateurs n'ont pas de définition par défaut. Leur en donner une n'est donc pas malsain (à mon avis).

    Tu fais peut-être allusion aux décalages de bits du C. Il me semble que les décalages de bits sont rarement utilisés (beaucoup moins qu'en C, en tout cas) dans les langages de haut-niveau ; utiliser >> et << pour des opérateurs fonctionnels me semblent donc une bonne idée, dans un langage fonctionnel.

    Tu peux critiquer ces symboles, mais je les trouve relativement clairs. Le chevron indique le sens. "abs >> succ" indique que le résultat de abs est renvoyé dans succ. C'est relativement clair, je trouve. Et le "|>" a la même logique que que le pipe. Ce qui est assez intuitif (plus que les symboles utilisés dans Haskell, à mon gout).

  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
    Et car et cdr c'est des bons choix de noms de fonctions je suppose ?
    (>>) et (|>) n'ont pas d'interprétation classique, néanmoins ils ont au moins une orientation évidente. Ils sont plutôt bien choisis tant qu'on autorise pas unicode pour avoir les vrais opérateurs mathématiques (compositions...).

    Franchement les critiques de la surcharge d'opérateur m'ont toujours semblé assez faibles, effectivement on peut faire du grand n'importe quoi avec, effectivement il n'aident pas à la compréhension si on ne connait pas la librairie employée, mais franchement même avec des fonctions bien nommées, il est difficile de déchiffrer une application écrites avec des API inconnues, et une fois dépassé cet obstacle initial, les opérateurs permettent une concision et une lisibilité supérieures à mon sens.

    Par ailleurs (>>) ou (|>) ne sont pas des opérateurs ad hoc choisis pour le cours, ce sont des opérateurs standards en F#.

    Quand à la question, a priori tu peux attribuer la précédence et l'associativité que tu veux aux opérateurs en OCaml.

    --
    Jedaï

  5. #5
    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
    Quand à la question, a priori tu peux attribuer la précédence et l'associativité que tu veux aux opérateurs en OCaml.
    Ah ? C'est possible sans jouer avec Camlp4 ? Quelles sont les règles utilisées par défaut ? Pour F#, les règles de priorité sont ici (la priorité et l'associativité dépend du premier caractère) :
    http://research.microsoft.com/fsharp...spx#Precedence

    |> et >> ont donc une priorité relativement faible.

  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 LLB Voir le message
    Tu peux critiquer ces symboles, mais je les trouve relativement clairs. Le chevron indique le sens. "abs >> succ" indique que le résultat de abs est renvoyé dans succ. C'est relativement clair, je trouve. Et le "|>" a la même logique que que le pipe. Ce qui est assez intuitif (plus que les symboles utilisés dans Haskell, à mon gout).
    Il est vrai que le ($) n'est pas intuitif (on s'habitue vite tout de même), par contre le (.) pour la composition est plus proche du symbole mathématique, bien sûr pour un langage avec des objets, son usage pose d'autres problèmes...

    Par ailleurs (>>) est déjà pris pour le 'then' des monades, où il est assez "intuitif" également.

    --
    Jedaï

  7. #7
    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 991
    Points
    2 991
    Par défaut
    J'essaye sur le problème des 8 reines.
    D'abord quelques fonctions auxiliaires:

    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
    let rec exists_commutative p l =
      match l with
      | []   -> false
      | h::t -> (List.exists (p h) t) or exists_commutative p t;;
     
    let rec distribute a l =
      match l with
      | []   -> [[a]]
      | h::t -> (a::l) :: (List.map (fun x -> h::x) (distribute a t));;
     
    let rec permute l =
      match l with
      | []   -> [[]]
      | h::t -> List.flatten (List.map (distribute h) (permute t));;
     
    let rec mapi f n l =
      match l with
      | [] -> []
      | h::t -> f n h::mapi f (n+1) t;;
     
    let check_queens (xa,ya) (xb,yb) =
      (xa - xb) = (ya - yb) or
      (ya - yb) = (xb - xa) ;;
    Ma solution sans pipe:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    let safe_boards queens =
      let no_pair f l = exists_commutative f l = false
      and pair a b = a,b in
      let map_pair i = mapi pair 1 in
        filter
        (no_pair check_queens) 
        (mapi map_pair 1 (permute queens))
      ;;
    Ma solution avec pipe:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    let safe_boards queens =
      let no_pair f l = exists_commutative f l = false
      and pair a b = a,b in
      let map_pair i = mapi pair 1 in
        queens  |>
        permute |>
        mapi map_pair 1 |>
        (check_queens |> no_pair |> filter)
      ;;
    Ca doit être une question d'habitude parce que là j'ai un peu du mal à reconnaître mon code. Et en cas d'erreur de typage, on retrouve ses petits ?
    En tout cas ça a l'air portable.

  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
    Le standard mathématique est de mettre la fonction avant l'argument. Il arrive qu'il soit plus pratique de faire l'inverse, par exemple quand on met bout à bout (que ce soit par composition ou piping) des fonctions de "traitement" : entree |> prepare |> compute |> sortie, par exemple.

    Cependant, ce n'est pas toujours le cas. En particulier la fonction "filter" gagne à être immédiatement suivie du prédicat de filtrage : "filtre suivant la condition machin" est une action que l'on imagine bien, "génère la condition machin et applique lui la fonction qui crée un filtre" est beaucoup moins clair.

    Je suggère plutôt quelque chose du style :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    queens |> permute |> mapi map_pair 1 |> filter (no_pair check_queens)
    Tu peux même si ça t'amuse coder l'ensemble de ta fonction en style point-free :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    let safe_boards =
      let pair a b = a, b in
      permute >> mapi (mapi pair 1) 1 >> filter (not << exists_commutative check_queens)
      ;;
    Par ailleurs, j'ai le sentiment que des tableaux seraient plus adaptés au problème.

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

Discussions similaires

  1. priorité des opérateurs
    Par new_wave dans le forum Langage
    Réponses: 3
    Dernier message: 02/12/2008, 13h09
  2. Priorité des opérateurs % et ++
    Par G3G3 dans le forum Débuter
    Réponses: 16
    Dernier message: 12/02/2008, 10h40
  3. priorité des opérateurs
    Par new_wave dans le forum SQL
    Réponses: 13
    Dernier message: 08/11/2007, 22h44
  4. Priorité des opérateurs
    Par neuromencien dans le forum Langage
    Réponses: 3
    Dernier message: 14/05/2007, 18h06
  5. Réponses: 3
    Dernier message: 31/08/2006, 11h39

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