Forum Programmation.autre Haskell

Posté par .
Tags : aucun
1
10
avr.
2010
Bonjour,
je pars d'une liste de liste : l1=[[1,2,3],[4,5,6],[7,8,9]] :: Int
et je voudrais faire la somme des 2 diagonales. Par exemple dans ce cas là : 1+5+9 grâce à une fonction sommeDiag1 et faire 3+5+7 avec sommeDiag2.
Je ne vois pas bien comment faire.
Si quelqu'un a une idée.

Voici ce que j'ai commencé :

sommeDiag1 :: Int -> Int
sommeDiag1 [] = 0
sommeDiag1 (x:xs) = let i = 1
in (head x)!!i + sommeDiag1 xs


Merci
  • # Indice

    Posté par (page perso) . Évalué à 1.

    Dans ton code i vaudra 1 à chaque appel, donc tu récupère uniquement la deuxième colonne (les indices des listes commencent à 0).
    • [^] # Re: Indice

      Posté par . Évalué à 2.

      Vu le cas d'école que représente la question, l'idée que l'énoncé soit en effet tiré d'un exercice ma traversé le vide qui sépare mes deux oreilles.

      Le hic, c'est que j'ai encore du mal à imaginer une université enseignant l'Haskell en France (ou dans les pays francophones), vu la faible notoriété du langage et l'héritage du Caml.
  • # Chouette du Haskell !

    Posté par . Évalué à 2.

    Donc au hasard, parce que je suis encore un bleu, je proposerais deux versions : l'une reprenant le message parent et une deuxième que je trouve plus propre. (je laisse la version avec State monad en exo :o)
    l1 = [ [ 1, 0, 4]
         , [ 0, 2, 0]
         , [ 1, 0, 3]
         ] ::  Int 
    
    diag1 ::  [ [Int] ] -> Int -> Int
    diag1 []     _ = 0
    diag1 (x:xs) i = (x !! i) + (diag1 xs (i+1))
    
    sommeDiag1 ::  [ [Int] ] -> Int
    sommeDiag1 l = diag1 l 0
    
    diag2 ::  [ [Int] ] -> Int -> Int
    diag2 []     _ = 0
    diag2 (x:xs) i = (x !! i) + (diag2 xs (i-1))
    
    sommeDiag2 ::  [ [Int] ] -> Int
    sommeDiag2 l = diag2 l (length l - 1)
    
    -- one liners
    
    sommeDiag1' :: (Num a) => [ [a] ] -> a
    sommeDiag1' l = sum $ zipWith (!!) l [0..]
    
    sommeDiag2' :: (Num a) => [ [a] ] -> a
    sommeDiag2' l = sum $ zipWith (!!) (reverse l) [0..]
    
    Toute critique est la bienvenue ! P.S.: j'ai vraiment de gros problème pour insérer du code sur ce site, notamment les '<', '>' et les '[ [ ] ] '. Quelqu'un connaît-il une solution ?
    • [^] # Re: Chouette du Haskell !

      Posté par (page perso) . Évalué à 2.

      Comme j'essaye de m'habituer à haskell, je me suis attaché à résoudre le problème, ça n'a pas été facile mais j'ai une solution qui me semblait satisfaisante bien qu'alambiquée :
      snd $ foldr (\ x y -> ( (fst y + 1), x!!(fromInteger (fst y)) + (snd y) ) ) (0, 0) [[1,2,3],[4,5,6],[7,8,9]]
      
      Mais apparemment, il y avait bien plus simple (j'aime bien le premier one-liner). Comme quoi, ce langage arrive à exprimer plein de choses de manière simple.
  • # Laid

    Posté par (page perso) . Évalué à 3.

    Les diagonales, c'est "l'indice i de la ligne i"…
    Donc tu parcoures tes listes, avec un compteur d'indice incrémenté à chaque nouvelle liste. Et tu additionnes "les éléments à l'indice i de chaque liste l_i".

    Pour diag2, c'est la même chose, sauf que tu inverses l'ordre de tes listes pour les parcourir à l'envers…


    l1=[[1,2,3],[4,5,6],[7,8,9]]

    diag1 = fst . foldl (\(x,c) y -> (x+(y!!c),c+1)) (0,0)
    diag2 = diag1 . reverse

    main = do
    print $ diag1 l1
    print $ diag2 l1
    • [^] # Autre petit problème

      Posté par . Évalué à 1.

      Bonjour,
      j'ai un nouveau soucis, cette fois c'est une histoire de IO.
      j'ai une fonction shuffle qui mélange une liste donnée (de type [a]) et qui renvoie cette liste mélangée alétoirement (de type IO [a]).
      Cependant, je veux utiliser cette fonction shuffle dans une autre fonction (qui ne prend pas de IO [a] en argument mais [a]).
      Je voudrais donc en quelque sorte convertir xs :: IO [Integer] en xs :: [Integer] pour ne pas avoir de soucis dans la fonction qui utilise shuffle.

      Voici ma fonction shuffle :

      shuffle' [] acc = return acc
      shuffle' l acc =
      do k <- randomRIO (0, length l - 1)
      let (lead, x:xs) = splitAt k l
      shuffle' (lead ++ xs) (x:acc)

      shuffle :: [a] -> IO [a]
      shuffle l = shuffle' l []


      Merci.
      • [^] # Re: Autre petit problème

        Posté par (page perso) . Évalué à 3.

        Pour faire simple, c'est impossible.

        Il faut donc que tu repenses ton problème autrement, c'est à dire que tu remarques que tu voudras éventuellement utiliser ton résultat, par exemple pour l'afficher. Et donc tu veux rester dans IO. Comme je vois juste une fonction et pas de main (dont le type est IO ()), j'en déduis que tu ne sais même pas ce que tu veux faire. Donc écrit main, et ensuite, code en te disant "je suis dans la monade IO"

        Exemple simple :

        import Random (randomRIO)
        import System (getArgs)

        shuffle' [] acc = return acc
        shuffle' l acc = do
          k <- randomRIO (0, length l - 1)
          let (lead, x:xs) = splitAt k l
          shuffle' (lead ++ xs) (x:acc)

        shuffle :: [a] -> IO [a]
        shuffle l = shuffle' l []

        ma_fonction_normale :: [String] -> [(String, Int)]
        ma_fonction_normale = map (\x -> (x, ((read x)+2)))

        main = do
          liste_d_entiers <- getArgs -- récupère une liste de nombres passés au programme
          itlse_d_enteisr <- shuffle liste_d_entiers -- permute
          let resultat = ma_fonction_normale itlse_d_enteisr -- applique une fonction "pas IO"
          print resultat -- affiche le résultat et quitte
      • [^] # Re: Autre petit problème

        Posté par . Évalué à 1.

        De trois chose l'une :
        1 - comme écrit dans la réponse précédente, quand tu joues avec la monad IO, tu ne peux plus en sortir. C'est un des fondements de Haskell : une fonction utilisant des données externes (IO) est impure et doit être confinée à l'écart du code restant. Autrement formulé : il est impossible de convertir un "IO a" en "a".

        2 - il est peut-être possible d'éviter la monad IO pour l'instant en préférant randomR et randomRs à randomRIO cf l'API Haskell pour plus de détails.

        3 - c'est pas joli de faire des postes en doubles !!
        • [^] # Re: Autre petit problème

          Posté par . Évalué à 1.

          Ouai, j'avais pas vu pour le double post, désolé.
          Pour en revenir à mon problème, j'ai bien compris que c'était bien compliqué cette histoire de monad IO.
          Je vous met aussi la fonction dans laquelle je veut réutiliser ma liste mélangée aléatoirement.

          data Mobile = Poids Rational | Branche Rational Mobile Mobile deriving Show

          poids :: Mobile -> Rational
          poids (Poids n) = n
          poids (Branche _ g d) = poids g + poids d

          shuffle' [] acc = return acc
          shuffle' l acc =
          do k <- randomRIO (0, length l - 1)
          let (lead, x:xs) = splitAt k l
          shuffle' (lead ++ xs) (x:acc)

          shuffle :: [a] -> IO [a]
          shuffle l = shuffle' l []

          ranCreation :: [Rational] -> Mobile
          ranCreation [] = (Poids 0)
          ranCreation [p] = (Poids p)
          ranCreation li = let m = splity li; x = (fst m); y = (snd m); k = (poids (ranCreation y))/(poids (ranCreation x) + poids (ranCreation y))
          in ((Branche k) (ranCreation x) (ranCreation y))

          splity :: [a] -> ([a],[a]) --Fonction qui découpe une liste en 2
          splity x = let n = div (length x) 2
          in splitAt n x


          Ma fonction ranCreation me permettrai donc de créer des mobiles aléatoires, en mélangeant à chaque fois les listes de poids.

          Merci à vous.
          • [^] # Re: Autre petit problème

            Posté par (page perso) . Évalué à 3.

            T'as pas compris. Haskell, c'est pas Lisp. L'interprète ghci a une sémantique pourrie, donc tant que tu ne fais pas un fichier à compiler avec un MAIN, tu ne comprendras jamais comment ça marche.
            Haskell, c'est un mensonge. On te dit "c'est pur, mais on peut faire des effets de bord dans la monade IO". La vérité, c'est que tu dois TOUT faire dans la monade IO. Tu dois TOUT faire à partir de la fonction main. Donc tu peux TOUJOURS extraire tes données avec l'opérateur "<-"

            Désormais, tu coderas dans un fichier, avec un main, et tu feras ":!ghci %" ou l'équivalent pour emacs. Et tu lanceras "main" dans ton interprète, si ça type.

            En pratique, une dernière fois (après, je moinsse !)


            import Random (randomRIO)
            import System (getArgs)

            data Mobile = Poids Rational | Branche Rational Mobile Mobile deriving Show

            poids :: Mobile -> Rational
            poids (Poids n) = n
            poids (Branche _ g d) = poids g + poids d

            shuffle' [] acc = return acc
            shuffle' l acc = do
              k <- randomRIO (0, length l - 1)
              let (lead, x:xs) = splitAt k l
              shuffle' (lead ++ xs) (x:acc)

            shuffle :: [a] -> IO [a]
            shuffle l = shuffle' l []

            splity :: [a] -> ([a],[a])
            splity x = splitAt n x where
                       n = div (length x) 2

            ranCreation :: [Rational] -> Mobile
            ranCreation [] = (Poids 0)
            ranCreation [p] = (Poids p)
            ranCreation li = Branche k (ranCreation x) (ranCreation y) where
                             m = splity li
                             x = fst m
                             y = snd m
                             k = (poids (ranCreation y))/(poids (ranCreation x) + (poids (ranCreation y)))


            main = do
                   liste <- getArgs
                   let liste_nombres = (map (fromIntegral . read) liste)
                   let arbre1 = ranCreation liste_nombres
                   liste_nombres_randomisee <- shuffle liste_nombres -- ICI !!!!
                   let arbre2 = ranCreation $ liste_nombres_randomisee -- LA !!!!
                   print arbre1
                   print arbre2


            Ensuite,
            ghc --make toto.hs
            ./toto 1 3 90

            Et voilà !

Suivre le flux des commentaires

Note : les commentaires appartiennent à ceux qui les ont postés. Nous n'en sommes pas responsables.