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

Haskell Discussion :

Haskell et invocation "dynamic" de fonction


Sujet :

Haskell

  1. #1
    oca
    oca est déconnecté
    Membre averti
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    354
    Détails du profil
    Informations personnelles :
    Âge : 51
    Localisation : Suisse

    Informations forums :
    Inscription : Octobre 2004
    Messages : 354
    Points : 421
    Points
    421
    Par défaut [Résolu] Haskell et invocation "dynamic" de fonction
    Hello,

    Est-ce que quelqu'un saurait si il est possible de faire une invocation de fonction qui serait choisie "au runtime"

    Pour illustrer mon besoin, j'aimerais faire un programme qui prend un String
    comme argument, et qui utilise cette String comme étant le nom de la fonction à invoquer.

    Pour simplifier, disons que mon programme "addOrSub" prenne "sub" ou "add" comme seul paramètre, et qu'il doive additioner ou soustraire deux nombres (disons 5 et 3 coder en dur c'est égal ici...)

    Pour le moment, j'arrive à ceci :

    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
     
    import System( getArgs )
     
    add a b = a + b 
    sub a b = a - b 
     
    -- correspondance entre une string et une fonction
    m = [
    	("add",add),
    	("sub",sub)
    	]  
     
    main = do 
    	args <- getArgs
    	let arg = args !! 0
    	-- recherche de la première fonction  dans la "m", correspondant à arg
    	let fonction = snd (filter (\it ->  fst it == arg  ) m !! 0)
    	-- invocation de la fonction avec 5 et 3 
    	print $ show $ fonction 5 3
    Ce que je souhaiterait, c'est de ne pas avoir à définir la liste "m", qui me sert de mapping entre le nom de la fonction et une String.

    En java, j'utiliserais la reflection pour faire cela, mais en haskell, comment faire ???

  2. #2
    Membre du Club
    Homme Profil pro
    Inscrit en
    Janvier 2010
    Messages
    46
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Janvier 2010
    Messages : 46
    Points : 57
    Points
    57
    Par défaut
    En Haskell il est possible de passer des fonctions en paramètre d'autres fonctions.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    -- Définition de la fonction permettant d'appeller d'autres fonctions
    fonction2arg f a1 a2 = f a1 a2
     
    -- Appel de la fonction (+)
    fonction2arg (+) 1 2
     
    -- Appel de la fonction (-)
    fonction2arg (-) 1 2

  3. #3
    oca
    oca est déconnecté
    Membre averti
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    354
    Détails du profil
    Informations personnelles :
    Âge : 51
    Localisation : Suisse

    Informations forums :
    Inscription : Octobre 2004
    Messages : 354
    Points : 421
    Points
    421
    Par défaut
    Citation Envoyé par Dim Me As New Idiot Voir le message
    En Haskell il est possible de passer des fonctions en paramètre d'autres fonctions.
    merci pour votre réponse. La ou je bloque, c'est surtout sur le problème de binding entre une string et une fonction.

    Voici un autre exemple :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    add a b = a + b
    sayHello name = "Hello " ++ name
    J'aimerais écrire une troisième fonction qui me permette de publier ces deux fonctions (add et sayHello) en temps que web service (SOAP)

    qqch du genre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    publish(sayHello)
    publish(add)
    Pour écrire "publish", je rencontre actuellement deux problèmes :
    1) l'introspection nécessaire à la publication de l'interface (WSDL)

    2) la réception de message et le binding du xml (soap) sur mes fonctions / type .

    En résumer, je cherche à savoir quelle serait la manière de faire qqch qui ressemblerait à ce code java, mais en haskell ...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    ...
    Method m = obj.getClass().getDeclaredMethod("sayHello", new Class[]{String.class});
    m.invoke(obj, new String[]{"Olivier"});
    ...

  4. #4
    Membre du Club
    Homme Profil pro
    Inscrit en
    Janvier 2010
    Messages
    46
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Janvier 2010
    Messages : 46
    Points : 57
    Points
    57
    Par défaut
    Je te suggère d'utiliser la bibliothèque suivante.

  5. #5
    oca
    oca est déconnecté
    Membre averti
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    354
    Détails du profil
    Informations personnelles :
    Âge : 51
    Localisation : Suisse

    Informations forums :
    Inscription : Octobre 2004
    Messages : 354
    Points : 421
    Points
    421
    Par défaut
    Merci pour le lien, je vais fouiller un peu pour voir si j'y trouve qq pistes.... Je cherche surtout à voir comment faire de la réflection / introspection "par moi-même" dans le but d'apprendre haskell.

  6. #6
    Membre du Club
    Homme Profil pro
    Inscrit en
    Janvier 2010
    Messages
    46
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Janvier 2010
    Messages : 46
    Points : 57
    Points
    57
    Par défaut
    Là je ne peux pas t'aider
    Peut être qu'un coup d'œil dans les sources pourra te donner des pistes.

  7. #7
    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
    Haskell n'est pas un langage qui supporte la réflection/introspection.

    Haskell est fortement typé, et tu comprends bien que ta méthode ne peut pas marcher : quel serait le type de la fonction "function_of_string" ? Tu prends une string, mais tu renvoies une fonction de "n'importe quel type", ça ne peut pas être bien typé.

    Il y a différente façon de faire quelque chose de plus ou moins équivalentes en Haskell. La plus simple est de transporter directement, au lieu de chaînes de caractères, la fonction (mais alors tu ne peux pas faire de sérialisation). Une autre façon de faire serait d'utiliser, non pas l'ensemble des fonctions Haskell, mais un type de donnée concret représentant des fonctions que tu pourrais à la fois sérialiser et "interpréter" pour les exécuter (ça revient à coder mini-langage dans ton programme, et un interpréteur pour ce langage).

    La réponse de fond à mon avis, c'est que Haskell est un langage très différent de Java, et que tu ne dois pas t'attendre à faire la même chose dans l'un et dans l'autre : si tu cherches à apprendre Haskell, exerce-toi à coder du Haskell, et pas à coder du Java en Haskell.

  8. #8
    oca
    oca est déconnecté
    Membre averti
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    354
    Détails du profil
    Informations personnelles :
    Âge : 51
    Localisation : Suisse

    Informations forums :
    Inscription : Octobre 2004
    Messages : 354
    Points : 421
    Points
    421
    Par défaut
    Citation Envoyé par bluestorm Voir le message
    Haskell n'est pas un langage qui supporte la réflection/introspection.
    Ok merci, c'est ce que je voulais savoir. pour ce qui est de l'introspection, il y a peut-être l'approche SYB qui pourrais faire mon bonheur...

    Haskell est fortement typé, et tu comprends bien que ta méthode ne peut pas marcher : quel serait le type de la fonction "function_of_string" ? Tu prends une string, mais tu renvoies une fonction de "n'importe quel type", ça ne peut pas être bien typé.
    Oui, mon but était de pouvoir implémenter le design pattern "strategy", ou l'on peut dynamiquement interchanger des implémentations répondant un à même contrat (interface).


    La réponse de fond à mon avis, c'est que Haskell est un langage très différent de Java, et que tu ne dois pas t'attendre à faire la même chose dans l'un et dans l'autre : si tu cherches à apprendre Haskell, exerce-toi à coder du Haskell, et pas à coder du Java en Haskell.
    100% d'accord avec cela !

  9. #9
    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
    Implémenter le pattern Strategy tel que je le comprends n'est pas très difficile en Haskell : comme les fonctions sont des valeurs comme les autres, il suffit de paramétrer ta logique applicative par l'opération à effectuer.

    Ce qui te posait une difficulté c'est de choisir l'opération ensuite en utilisant son nom sous forme de string. Je pense que ce n'est pas nécessaire : comme les différentes stratégies/opérations sont de même type, tu peux les stocker dans une liste ou la structure que tu veux, indexées par ce que tu veux (tu peux utiliser par exemple une fonction qui selon la configuration renvoie la stratégie adaptée), et à priori par quelque chose de plus sémantique qu'une simple string (sauf bien sûr dans le cas d'une option en ligne de commande, etc.).

    Après, la mise en place précise de ce "pattern" sera sans doute très différente, puisque Haskell n'encourage pas du tout les effets de bord : une opération "setStrategy : string -> unit" est impensable; tu pourrais émuler ce comportement avec une monade d'effet de bord, mais ce n'est pas une bonne méthode, et il faut trouver celle qui est la plus adaptée à ton application (peut-être une Reader monad, mais le plus simple pour commencer reste de passer le choix de configuration en paramètre).

  10. #10
    oca
    oca est déconnecté
    Membre averti
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    354
    Détails du profil
    Informations personnelles :
    Âge : 51
    Localisation : Suisse

    Informations forums :
    Inscription : Octobre 2004
    Messages : 354
    Points : 421
    Points
    421
    Par défaut
    Citation Envoyé par bluestorm Voir le message
    Implémenter le pattern Strategy tel que je le comprends n'est pas très difficile en Haskell ...
    Merci, effectivement, finalement un case of fait très bien l'affaire dans presque tous les cas. Il reste y a juste le cas de la stratégie "inconnue" au moment de la compilation du programme (en d'autre terme, la problématique du plugin).

    J'ai vu qu'il existe un module plugins-hs, j'irai peut-être voir de ce côté la lorsque j'aurai suffisamment avancé dans mon apprentissage...

    Je vais passer le sujet en résolu.

  11. #11
    oca
    oca est déconnecté
    Membre averti
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    354
    Détails du profil
    Informations personnelles :
    Âge : 51
    Localisation : Suisse

    Informations forums :
    Inscription : Octobre 2004
    Messages : 354
    Points : 421
    Points
    421
    Par défaut
    Bon... j'ai un peu avancé et j'arrive à cela :

    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
     
    import Maybe
    m = [
    	("f1",(2 +)),
    	("f2",(20 +)),
    	("f3",(200 +))
    	]
     
    exec what = putStrLn . show . invoke (findFuncs what m ) 
    	where 
    		findFuncs :: String -> [(String, (Int -> Int))] -> [(Int -> Int)] 
    		findFuncs str funcMap = map (\w -> fromJust (lookup w funcMap) ) (words str)
     
    		invoke :: [(Int ->Int)] -> Int ->  Int 
    		invoke (x:xs) n = invoke xs (x n)
    		invoke [] n = n
     
    main = exec "f1 f1 f2" 4
    J'ai donc une fonction exec qui prend un string contenant le nom des fonctions à invoquer et qui calcul un resultat (dans mon cas 4 + 2 + 2 + 20 = 28 ).

    Le programme marche, mais si qq y voit des améliorations, je suis preneur !
    A+

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

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