2010-11-20 33 views
12

J'ai créé une zone de liste déroulante de convertir un xmlWidget en un comboBox avec la fonction castTocomboBox et maintenant je veux obtenir le texte ou l'index de l'élément actif. Le problème est que si j'utilise la fonction comboBoxGetActive il renvoie un résultat IO Int et j'ai besoin de savoir comment puis-je obtenir la valeur Int. J'ai essayé de lire au sujet des monades afin que je puisse comprendre ce que l'on pourrait faire dans une telle situation, mais je ne semble pas comprendre. J'apprécie toute l'aide que je peux obtenir. Je devrais probablement mentionner que j'utilise Glade et gtk2hs.Conversion IO Int en Int

+8

Copie possible de [Une fonction Haskell de type: IO String-> String] (http://stackoverflow.com/questions/1675366/a-haskell-function-of-type-io-string-string). –

Répondre

27

En règle générale, vous écrivez quelque chose comme ceci:

do 
    x <- somethingThatReturnsIO 
    somethingElseThatReturnsIO $ pureFunction x 

Il n'y a pas moyen d'obtenir la « Int » sur un « IO Int », à l'exception de faire quelque chose d'autre dans la monade IO.

En termes monade, le code ci-dessus desugars dans

somethingThatReturnsIO >>= (\x -> somethingElseThatReturnsIO $ pureFunction x) 

Le ">> =" opérateur (prononcé "bind") fait la magie de la conversion de la "IO Int" dans un "Int", mais il refuse de vous donner cet Int directement. Il ne fera que passer cette valeur dans une autre fonction en tant qu'argument, et cette fonction doit retourner une autre valeur dans "IO". Méditez sur le type de liaison avec la monade IO pendant quelques minutes, et vous serez éclairés:

>>= :: IO a -> (a -> IO b) -> IO b 

Le premier argument est votre valeur initiale « IO Int » que « comboBoxGetActive » est de retour. La seconde est une fonction qui prend la valeur Int et la transforme en une autre valeur d'E/S. Ainsi, vous pouvez traiter l'Int, mais les résultats de cette opération n'échappent jamais à la monade IO.

(Bien sûr, il est le « unsafePerformIO » infâme, mais à votre niveau de connaissance vous pouvez être certain que si vous l'utilisez alors vous le faites mal.)

(En fait, le désucrage est un peu plus compliquée . pour permettre modèle a échoué correspond Mais vous pouvez prétendre que j'ai écrit est vrai)

+1

Salut Paul, j'essaie actuellement de lancer des Ints aléatoires de System.random à ints mais ça ne va pas bien. Y a-t-il une possibilité que tu puisses m'aider? J'ai mis le code sur pastebin pendant un jour: [link] (http://pastebin.com/1s3bNztY) –

+0

Votre problème est que vous ne pouvez pas avoir de vrais nombres aléatoires dans un calcul pur: c'est ce que veulent dire vos erreurs de type. Donc, vous devez regarder des fonctions pures comme randomR qui prennent un générateur et retournent un résultat aléatoire et un nouveau générateur. Vous prenez le générateur retourné et l'utilisez pour votre prochaine valeur aléatoire. Votre fonction doit prendre et retourner un générateur comme randomR. Appelez ensuite votre fonction pure avec getStdRandom au plus haut niveau. Jetez un oeil à la source de "randoms" pour quelques indices. BTW, avez-vous envisagé ce qui se passe si votre liste de nombres aléatoires a le même nombre deux fois? –

+0

Salut Paul, je n'y avais pas encore pensé. Pouvez-vous me donner une implémentation simple? Je ne peux pas comprendre avec le générateur. –

11

Eh bien, il est unsafePerformIO: http://haskell.org/ghc/docs/6.12.1/html/libraries/base-4.2.0.0/System-IO-Unsafe.html#v:unsafePerformIO

(Si vous voulez savoir comment trouver cette méthode: Aller à http://www.haskell.org/hoogle et rechercher la signature dont vous avez besoin, ici IO a -> a)

Cela dit, vous avez probablement entendu parler de "Ce qui se passe dans IO reste dans IO". Et il ya très de bonnes raisons pour cela (il suffit de lire la documentation de safePerformIO). Donc, vous avez très probablement un problème de conception, mais afin d'obtenir de l'aide de Haskellers expérimentés (je ne suis certainement pas), vous devez décrire votre problème plus en détail.

+3

@downvoter: Voulez-vous s'il vous plaît expliquer? Je pense que ma réponse est correcte: j'ai expliqué comment vous pourriez faire ce qu'on vous demandait, et que c'est très probablement une mauvaise idée. – Landei

3

pour comprendre ce que ces types sont par -Step alliance, d'abord regarder jusqu'à ce que peut-être et la liste sont:

data Maybe a = Nothing | Just a 
data [a]  = [] | a : [a] 

(Peut-être un) est un type différent de (un), comme (peut-être Int) diffère de (Int). valeurs exemple du type (Maybe Int) sont seulement 5 et Rien.

Une liste des (un) s peut être écrit ([] un) et que ([a]). Les valeurs d'exemple de ([Int]) sont [1,7,42] et [].

Maintenant, un (IO a) est une autre chose que (un) aussi: Il est une entrée/sortie-calcul qui calcule une valeur de type (un). En d'autres termes: c'est un script ou un programme, qui doit être exécuté pour générer une valeur de type (a). Un exemple de (IO Chaîne) est getLine, qui lit une ligne de texte à partir de l'entrée standard.

Maintenant, le type de comboBoxGetActive est:

comboBoxGetActive :: ComboBoxClass self => self -> IO Int 

Cela signifie que comboBoxGetActive est une fonction (->) que les cartes de tout type qui a une instance de type classe ComboBoxClass (primitive les classes de type sont en quelque sorte similaires aux interfaces java) à un (IO Int). Chaque fois, cette fonction (->) est évaluée avec la même valeur d'entrée de ce type (self) (quel que soit ce type), il en résulte la même valeur: C'est toujours la même valeur de type (IO Int), cela signifie que c'est toujours le même script. Mais lorsque vous exécutez le même script à des moments différents, il peut produire différentes valeurs de type (Int).

La fonction principale de votre programme a le type (IO()), cela signifie que le compilateur et le système d'exécution évaluent les équations que vous programme dans ce langage fonctionnel à la valeur principale, qui seront exécutées dès que vous démarrez le programme.