2011-10-18 6 views
0

J'ai la fonction suivante que itère sur une liste [(Map String SqlValue)]Haskell fonction récursive sur la liste IO

extractPatternStrings ∷ IO [(Map String SqlValue)] → IO [String] 
extractPatternStrings [] = do 
    return [] 
extractPatternStrings lst = do 
    (m:ms) ← lst 
    return $ (toString m) : (extractPatternStrings ms) 
    where 
     toString ∷ Map String SqlValue → String 
     toString m = (fromSql . fromJust . (Map.lookup "word"))∷ String 

execpt le cas de liste vide me dit qu'il ne pouvait pas correspondre à la IO [Map String SqlValue] attendue avec [t0] réelle. Je pensais que le do = return aurait pris soin de cela. Comment dois-je corriger cela?

Edit: Pour répondre à pourquoi je suis en utilisant IO:

La fonction est appelée à partir selectAll ↠ extractPatternStrings où selectAll lit à partir d'une base de données.

+5

Pourquoi utilisez-vous IO ici? Cela ressemble à ce qu'il aurait pu être une pure fonction à la place. – hugomg

+0

J'utilise IO car je lis depuis une base de données.Si je n'utilise pas d'E/S, le code de lecture de la base de données me donne une erreur en voulant 'renvoyer' un E/S. – providence

Répondre

7
extractPatternStrings ∷ IO [(Map String SqlValue)] → IO [String] 

Un IO [String] est une action IO qui produit un résultat [String]. L'utilisation de la notation Do garantit que extractPatternStrings produit un IO [String], et non un [String]. Un IO [(Map String SqlValue)] est une action d'E/S qui produit un résultat [Map String SqlValue]. Mais vous ne pouvez pas faire correspondre le pattern à une action IO. La syntaxe que vous utilisez est destinée à correspondre directement à une liste, et non à une action d'E/S produisant une liste.

Vous devez utiliser cette signature de type à la place:

extractPatternStrings ∷ [Map String SqlValue] → IO [String] 

Sauf que, comme @missingno souligne, cela n'a pas besoin d'être une action IO:

extractPatternStrings ∷ [Map String SqlValue] → [String] 
extractPatternStrings []  = [] 
extractPatternStrings (m:ms) = toString m : extractPatternStrings ms 
    where 
     toString ∷ Map String SqlValue → String 
     toString m = (fromSql . fromJust . (Map.lookup "word"))∷ String 

Ou, mieux (et la fixation d'une erreur dans toString):

extractPatternStrings ∷ [Map String SqlValue] → [String] 
extractPatternStrings = map toString 
    where 
     toString ∷ Map String SqlValue → String 
     toString = fromSql . fromJust . Map.lookup "word" 

Plus succinctement:

extractPatternStrings ∷ [Map String SqlValue] → [String] 
extractPatternStrings = map (fromSql . fromJust . Map.lookup "word") 

Si vous devez vraiment avoir la signature originale, puis utilisez liftM, que ce soit en changeant votre code appelant à selectAll ↠ liftM extractPatternStrings (et je dois avouer que je ne reconnais pas l'opérateur que vous utilisez là-bas), ou en définissant extractPatternStrings comme

extractPatternStrings ∷ IO [Map String SqlValue] → IO [String] 
extractPatternStrings = liftM $ map (fromSql . fromJust . Map.lookup "word") 

Mais je recommande le premier.

+0

J'ai réussi à le faire fonctionner avec le premier. Merci de votre aide! Oh et cet opérateur était le '>> ='. Mon éditeur convertit juste cela en symbole Unicode. – providence

2

Le return entoure votre valeur de retour dans IO, de sorte que prend soin du type de retour IO [String]. Cependant, cela ne vous aide pas avec votre type d'argument, qui est [(Map String SqlValue)], mais que vous essayez de modéliser correspond à la liste vide. Fondamentalement, vous ne pouvez pas correspondre à des valeurs d'E/S. Donc, vous devriez soit vous débarrasser des E/S (qui semblent totalement inutiles dans votre code) ou si vous voulez vraiment que la fonction prenne une E/S (bien que je ne puisse pas imaginer pourquoi vous le feriez), vous devez Déballez votre argument avant de pouvoir faire correspondre le modèle, qui ressemblerait à ceci:

extractPatternStrings lstIO = do 
    lst <- lstIO 
    case lst of 
    [] -> ... 
    (m:ms) -> ...