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 :

fonction haskell appelée depuis module C


Sujet :

Haskell

  1. #1
    Membre à l'essai
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    32
    Détails du profil
    Informations personnelles :
    Âge : 53
    Localisation : France

    Informations forums :
    Inscription : Janvier 2005
    Messages : 32
    Points : 19
    Points
    19
    Par défaut fonction haskell appelée depuis module C
    Bonjour,

    j'ai découvert ce langage au travers du post sur une intervention de Jedai (merci Maitre, oserais-je dire ... )

    Du coup, j'ai décidé de faire un peu mumuse avec ...
    Je suis parti de son exemple, et j'essai, d'une part de comprendre ce que je manipule , et d'autre part de compléter le source pour permettre l'appel de la fonction depuis l'extérieur.

    la fonction que je veux appeler depuis l'extérieur est la suivante :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    findBestBalance wsLeft wsRight = 
        if size i == 1 then Nothing else Just $ findMax i
            where i = sums wsLeft `intersection` sums wsRight
    J'ai donc tenté de rajouter une ligne ressemblant à ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    foreign export ccall "haskellBalance" findBestBalance :: [Integer] [Integer]
    pour dire que l'extérieur verra une fonction haskellBalance faisant référence à findBestBalance et prenant (si j'ai bien compris le truc) 2 listes d'Integer comme paramètre. Mais là, je pense que j'ai un problème de définition du "prototype de la fonction" (désolé, j'utilise un vocabulaire qui n'est peut être pas le bon pour le langage).

    En effet, la tentative de compil (ghc -O2 -c balance.hs) me donne l'erreur suivante :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    balance.hs:10:19:
        Kind error: `[Integer]' is applied to too many type arguments
        In the type `[Integer] [Integer]'
        In the type signature for `findBestBalance':
          findBestBalance :: [Integer] [Integer]
    Du coup, j'ai essayé d'approfondir la déclaration des fonctions, mais plus j'en lis sur le sujet, moins je comprends ...

    Mais, quoi qu'est ce qui cloche !!??

    D'avance, merci.

    Je donne le source complet ci-dessous :
    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
     
    module Balance where
     
    foreign export ccall "haskellBalance" findBestBalance :: [Integer] [Integer]
     
    import Data.Set (size, singleton, union, intersection, mapMonotonic, findMax)
    import Data.List (foldl')
     
    sums = foldl' (\m x -> m `union` mapMonotonic (+x) m) (singleton 0)
     
    findBestBalance :: [Integer] [Integer]
    findBestBalance wsLeft wsRight = 
        if size i == 1 then Nothing else Just $ findMax i
            where i = sums wsLeft `intersection` sums wsRight
     
    -- pas mesurable
    eg1,eg2 :: [Integer]
    eg1 = [7991,6765,2584,987,377,144,55,21,8,3,1]
    eg2 = [10946,4181,1597,610,233,89,34,13,5,2]
     
    -- 410ms
    ceg1, ceg2 :: [Integer]
    ceg1 = take 100 [2,5..]
    ceg2 = take 100 $ 1:[100000,200000..]
     
     
    -- 1,61s
    seg1, seg2 :: [Integer]
    seg1 = take 100 $ 10015900 : [2,5..]
    seg2 = take 100 $ 1:1:49:15000:[100000,200000..]
    J'essaierai ensuite de faire retourner le résultat par cette fonction plutôt que de l'afficher à l'écran. Mais bon, je verrais ça après. On va y aller petit à petit ...

  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
    Les fonctions en Haskell sont curryfiées, autrement dit, elles ne prennent jamais qu'un seul argument au maximum. Néanmoins l'illusion de fonction à plusieurs arguments est créée par le fait qu'on retourne une fonction prenant la suite des arguments. Flou ?
    Alors prenons l'exemple de findBestBalance :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    findBestBalance wsLeft wsRight = 
        if size i == 1 then Nothing else Just $ findMax i
            where i = sums wsLeft `intersection` sums wsRight
    La notation peut t'incliner à penser que findBestBalance prend deux arguments, mais il n'en est rien : cette fonction prend une liste d'entiers et retourne une fonction qui prend une liste d'entier et renvoie "juste un entier" ou "rien", son type est donc :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    findBestBalance :: [Int] -> ([Int] -> Maybe Int)
    où "a -> b" signifie que la fonction prend un argument de type a et renvoie un résultat de type b. Par ailleurs, (->) est associatif à droite, on peut donc se contenter de noter :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    findBestBalance :: [Int] -> [Int] -> Maybe Int
    Quand on "applique cette fonction à deux arguments", l'associativité à gauche de l'application fait en fait en sorte qu'on commence par évaluer findBestBalance sur le premier argument, ça nous renvoie une fonction, qu'on applique sur le second argument. C'est à dire que :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    findBestBalance seg1 seg2
    est exécuté comme suit :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    (findBestBalance seg1) seg2
    La currification est largement répandue dans les langages fonctionnels modernes, parce qu'elle apporte énormément d'avantage, en particulier, il est très courant d'évaluer partiellement une fonction en lui donnant seulement son premier argument puis de l'utiliser à plusieurs endroit, c'est un gain en efficacité et souvent en lisibilité :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    cubeList :: [Int] -> [Int]
    cubeList = map (\n -> n^3)
    Cette fonction prend une liste et met au cube tous ses éléments. Je peux faire ça parce que "map" est une fonction curryfiée qui prend une fonction et une liste et renvoie la liste dans laquelle on a appliqué la fonction à tous les éléments.

    J'essaierai ensuite de faire retourner le résultat par cette fonction plutôt que de l'afficher à l'écran. Mais bon, je verrais ça après. On va y aller petit à petit ..
    Cette fonction retourne le résultat, elle ne l'affiche pas, dans le programme originel, l'affichage du résultat était fait par le main.

    --
    Jedaï

  3. #3
    Membre à l'essai
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    32
    Détails du profil
    Informations personnelles :
    Âge : 53
    Localisation : France

    Informations forums :
    Inscription : Janvier 2005
    Messages : 32
    Points : 19
    Points
    19
    Par défaut
    Citation Envoyé par Jedai Voir le message
    Les fonctions en Haskell sont curryfiées, autrement dit, elles ne prennent jamais qu'un seul argument au maximum ...
    Whaou, merci pour ces clarifications ...
    Effectivement, j'étais aux antipodes de ce qu'il fallait comprendre, et je m'en éloignais au fil des lectures.

    Citation Envoyé par Jedai Voir le message
    Cette fonction retourne le résultat, elle ne l'affiche pas, dans le programme originel, l'affichage du résultat était fait par le main.
    Oups, ce qui prouve que je n'avais rien compris ...

    J'ai aussi noté la simplification sur la notation des listes. Je n'y étais pas arrivé (sans voir que cette notation était déjà de base employée avec la liste seg2 commençant par 1), et du coup je l'avais étendue.


    Il me reste quand même encore un problème. La ligne foreign export ccall me retourne encore une erreur à la compil :

    Le code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    module Balance where
     
    foreign export ccall "haskellBalance" findBestBalance :: [Integer] -> [Integer] -> maybe Integer
    ...
    findBestBalance :: [Integer] -> [Integer] -> maybe Integer
    ...
    l'erreur (pas très parlante, du moins pour le jeune padawan que je suis) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    balance.hs:3:0: Invalid type signature

    Merci

  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 barbouille Voir le message
    Le code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    module Balance where
     
    foreign export ccall "haskellBalance" findBestBalance :: [Integer] -> [Integer] -> maybe Integer
    ...
     
    findBestBalance :: [Integer] -> [Integer] -> maybe Integer
    ...
    l'erreur (pas très parlante, du moins pour le jeune padawan que je suis) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    balance.hs:3:0: Invalid type signature
    Pas très causant effectivement... Si tu reregardes ma signature de type et la tienne très attentivement tu vas voir plusieurs différence :
    1. J'utilise Int, pas Integer, Int est équivalent au int du C, Integer est un type d'entier en précision arbitraire, qui vient de GMP (la librairie mathématiques)
    2. "maybe a" n'existe pas, seul "Maybe a" existe. De toute façon, un type en Haskell commence par une majuscule, tandis qu'une variable (ou une fonction) commence par une minuscule, donc maybe n'est visiblement pas bon.

    Un mot sur "Maybe Int" : Maybe est un constructeur de type, autrement dit il prend un type en paramètre pour construire un nouveau type. Comme un template en C++ si tu veux (soit dit en passant [] est un constructeur de type aussi, celui des listes). "Maybe a" est l'équivalent d'un type "Nullable" si tu as fait du C#, autrement dit il désigne un type dont la valeur sera soit de type a (Just something), soit rien du tout (Nothing). Des exemples d'usage fréquent sont les fonctions qui peuvent échouer à trouver un résultat acceptable, comme ici. Mais pour passer au C, il serait peut être plus raisonnable de se contenter de renvoyer 0 en cas d'échec, il te suffit de modifier un tout petit peu la fonction :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    findBestBalance :: [Int] -> [Int] -> Int
    findBestBalance wsLeft wsRight = findMax i
        where i = sums wsLeft `intersection` sums wsRight
    --
    Jedaï

  5. #5
    Membre à l'essai
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    32
    Détails du profil
    Informations personnelles :
    Âge : 53
    Localisation : France

    Informations forums :
    Inscription : Janvier 2005
    Messages : 32
    Points : 19
    Points
    19
    Par défaut
    Citation Envoyé par Jedai Voir le message
    Pas très causant effectivement...
    ...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    findBestBalance :: [Int] -> [Int] -> Int
    findBestBalance wsLeft wsRight = findMax i
        where i = sums wsLeft `intersection` sums wsRight
    Bon, j'ai :
    - sorti les tubes d'aspirine
    - remonté les manches
    - lacé les chaussures
    - appliqué tes recommandations ...

    Ce qui me donne désormais le code suivant avec toujours la même erreur toujours aussi peu parlante et une question (voir après le code) :
    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
     
    module Balance where
     
    foreign export ccall "haskellBalance" findBestBalance :: [Int] -> [Int] -> Int
     
    import Data.Set (size, singleton, union, intersection, mapMonotonic, findMax)
    import Data.List (foldl')
     
    sums = foldl' (\m x -> m `union` mapMonotonic (+x) m) (singleton 0)
     
    findBestBalance :: [Int] -> [Int] -> Int
    findBestBalance wsLeft wsRight = findMax i
            where i = sums wsLeft `intersection` sums wsRight
     
    -- pas mesurable
    eg1,eg2 :: [Int]
    eg1 = [7991,6765,2584,987,377,144,55,21,8,3,1]
    eg2 = [10946,4181,1597,610,233,89,34,13,5,2]
     
    -- 410ms
    ceg1, ceg2 :: [Int]
    ceg1 = take 100 [2,5..]
    ceg2 = take 100 $ 1:[100000,200000..]
     
     
    -- 1,61s
    seg1, seg2 :: [Int]
    seg1 = take 100 $ 10015900 : [2,5..]
    seg2 = take 100 $ 1:1:49:15000:[100000,200000..]
    Les listes eg1, eg2, etc ... ont des tailles (nombre d'éléments) bien définies.
    Je ne sais pas comment haskell gère ça, mais le nombre d'éléments doit exister au niveau de la liste, non (faut bien savoir dans les fonctions où s'arrêter) ?

    Le proto C que je cherche à avoir ressemblera probablement à ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    int haskellBalance (int *liste1, int *liste2);
    Comment savoir où s'arrête la liste au niveau de la fonction haskell sachant qu'elle vient du C ?

    Avec un peu de chance le message d'erreur tourne autour d'un truc comme ça, non ?

  6. #6
    Membre à l'essai
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    32
    Détails du profil
    Informations personnelles :
    Âge : 53
    Localisation : France

    Informations forums :
    Inscription : Janvier 2005
    Messages : 32
    Points : 19
    Points
    19
    Par défaut
    Citation Envoyé par barbouille Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    balance.hs:3:0: Invalid type signature
    Bonjour les gens ...

    J'ai pioché quelques exemples sur le net concernant la FFI (ça veut dire Foreign function interface ... ben, hé !! je me culture !!!) et j'obtiens toujours la même erreur, même sur les exemples donnés pris brut de fonderie, et ce toujours sur la ligne foreign export.
    Si je la met en commentaire, le source compile et me génère bien un objet.

    Il doit y avoir un truc gros comme une maison, mais je ne le vois pas ...

    J'en suis à essayer de compiler ça (qui a dû se déformer un peu depuis que je l'ai pompé sur je ne sais plus quel site, et que j'essaie de compiler en bidouillant des trucs que je ne maitrise vraiment pas ...) :

    Code : j'y arriverais un jour, j'y arriverais ... : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    module Foo where
     
    import Foreign.C.Types ( CInt )
     
    foreign export ccall "plus" addInt :: CInt -> CInt -> CInt
     
    addInt :: CInt -> CInt -> CInt
    addInt op1 op2 = op1 + op2

    Personne n'aurait une idée ?

  7. #7
    Membre à l'essai
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    32
    Détails du profil
    Informations personnelles :
    Âge : 53
    Localisation : France

    Informations forums :
    Inscription : Janvier 2005
    Messages : 32
    Points : 19
    Points
    19
    Par défaut
    Citation Envoyé par barbouille Voir le message
    Bonjour les gens ...

    Il doit y avoir un truc gros comme une maison, mais je ne le vois pas ...
    C'est bien ce que je disais, gros comme une maison.

    Suffit de demander de l'aide pour trouver la solution tout seul ...

    Il faut -fglasgow-exts sur la ligne de commandes de GHC ...

    J'avance ...

    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
     
    module Balance where
     
    import Data.Set (size, singleton, union, intersection, mapMonotonic, findMax)
    import Data.List (foldl')
    import Foreign.C.Types ( CInt )
     
     
    foreign export ccall balance1 :: CInt
    foreign export ccall balance2 :: CInt
    foreign export ccall balance3 :: CInt
     
    sums = foldl' (\m x -> m `union` mapMonotonic (+x) m) (singleton 0)
     
    balance1 :: CInt
    balance1 = findBestBalance eg1 eg2
     
    balance2 :: CInt
    balance2 = findBestBalance ceg1 ceg2
     
    balance3 :: CInt
    balance3 = findBestBalance seg1 seg2
     
     
    findBestBalance :: [CInt] -> [CInt] -> CInt
    findBestBalance wsLeft wsRight = findMax i
            where i = sums wsLeft `intersection` sums wsRight
     
    -- pas mesurable
    eg1,eg2 :: [CInt]
    eg1 = [7991,6765,2584,987,377,144,55,21,8,3,1]
    eg2 = [10946,4181,1597,610,233,89,34,13,5,2]
     
    -- 410ms
    ceg1, ceg2 :: [CInt]
    ceg1 = take 100 [2,5..]
    ceg2 = take 100 $ 1:[100000,200000..]
     
     
    -- 1,61s
    seg1, seg2 :: [CInt]
    seg1 = take 100 $ 10015900 : [2,5..]
    seg2 = take 100 $ 1:1:49:15000:[100000,200000..]
    Il me faut encore bûcher comment passer les paramètres nécessaires à findBestBalance à partir du C, mais pour l'instant je vais me contenter de balance1, balance2 et balance3 pour faire du bench ... et essayer de le faire marcher, parce que ça compile c'est déjà un premier pas, mais faut encore le lier au reste du merdier ...

  8. #8
    Membre à l'essai
    Profil pro
    Inscrit en
    Décembre 2007
    Messages
    27
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2007
    Messages : 27
    Points : 20
    Points
    20
    Par défaut
    bonjour à tous,

    je remonte ce post car je suis en train de me mettre à l'haskell et j'ai cette erreur qui me pose problème.

    en effet, je fais une fonction toute bête et j'ai ce fameux "invalid type signature"

    je vous met la fonction pour savoir si vous avez une petite idée du pourquoi :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    VerifMatrice :: [ [ Float ] ] -> Bool
    VerifMatrice l
         | l == [ head l ] = True
         | lenght ( head l ) == length ( tail l) = VerifMatrice ( tail l)
         | otherwise = False
    merci d'avance.

  9. #9
    Membre à l'essai
    Profil pro
    Inscrit en
    Décembre 2007
    Messages
    27
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2007
    Messages : 27
    Points : 20
    Points
    20
    Par défaut
    me revoila après avoir trouvé mon erreur toute bête :
    il ne faut surtout pas appeler ses fonctions avec une majuscule au début !
    désolé pour ceux (ils y en a surement un ou deux) qui se sont creusé la tête pour cette question débile.
    Merci quand même.

  10. #10
    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
    Pas grand chose à voir en fait...
    En tout cas, l'une des grandes règles en Haskell est "les variables et les fonctions commencent par une minuscule", "les types et les constructeurs commencent par une majuscule".
    Or VerifMatrix est une fonction, tu devrais donc l'appeler verifMatrix, ceci corrigé (et en mettant "length" plutôt que "lenght"), ta fonction compile :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    VerifMatrice :: [ [ Float ] ] -> Bool
    VerifMatrice l
         | l == [ head l ] = True
         | lenght ( head l ) == length ( tail l) = VerifMatrice ( tail l)
         | otherwise = False
    Par ailleurs j'écrirais plutôt ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    verifMatrice' (xs:xxs) = and $ zipWith (\n ys -> length ys == len - n) [1..] xxs
        where len = length xs
    Plus clair à mon goût (tu veux un triangle, éventuellement tronqué, n'est-ce pas ?).
    (Ou pas... En fait je ne suis plus sûr de comprendre ton intention avec ta fonction... Quelle forme a donc ta "matrice" !)

    --
    Jedaï

Discussions similaires

  1. Appeler une fonction de ThisWorkbook depuis un module
    Par MyJero dans le forum Macros et VBA Excel
    Réponses: 4
    Dernier message: 07/11/2013, 17h15
  2. Appel d'une fonction stockée MySQL depuis un module VB.Net
    Par mddkkr dans le forum SQL Procédural
    Réponses: 0
    Dernier message: 22/09/2013, 17h12
  3. passage de paramètre d'une fonction fortran appelée depuis python
    Par Dreyliciouss dans le forum Interfaçage autre langage
    Réponses: 0
    Dernier message: 20/07/2010, 10h44
  4. Réponses: 4
    Dernier message: 27/11/2009, 17h08

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