2017-09-23 2 views
1

Salut J'ai une semblable à la fonction haskell suivantetest de fonctions haskell qui renvoient des erreurs

test :: Int -> Bool 
test 1 = error "shouldnt have been 1" 
test 2 = error "shouldnt have been 2" 
test 11 = error "shouldnt have been 11" 
test 77 = error "shouldnt have been 77" 
test _ = True 

J'ai un système d'essai pour tester les mauvaises entrées pour vous assurer qu'ils renvoient l'erreur correcte

tc1 = test 1 
tc2 = test 2 
tc3 = test 11 
tc4 = test 77 

allTests = [tc1, tc2, tc3, tc4] 

Mais le problème est que lorsque je cours allTests dans ghci, je reçois seulement la première erreur. Je voudrais avoir une liste de toutes les erreurs

Comment cela peut-il être fait ou d'une certaine façon je peux attraper les erreurs?

Répondre

4

Vous pouvez essayer d'utiliser catch à partir de Control.Exception, mais c'est toujours une manière délicate d'atteindre l'objectif.

Il serait préférable d'utiliser un type de données pur pour capturer les erreurs, car elles sont plus faciles à composer et à collecter. Normalement, vous utiliseriez Either pour cela, mais dans ce cas particulier, le cas de succès ne porterait aucune information, donc le type serait Either String(), qui est isomorphe à Maybe String. Réécriture test retourner Maybe String est trivial:

test :: Int -> Maybe String 
test 1 = Just "shouldnt have been 1" 
test 2 = Just "shouldnt have been 2" 
test 11 = Just "shouldnt have been 11" 
test 77 = Just "shouldnt have been 77" 
test _ = Nothing 

tc1 = test 1 
tc2 = test 2 
tc3 = test 11 
tc4 = test 77 
tc5 = test 5 

J'ai ajouté une valeur tc5 afin de démontrer ce qui se passe lorsqu'un test réussit.

Vous pouvez évaluer tous les cas de test, mais si vous voulez que les cas d'échec, vous pouvez utiliser catMaybes de Data.Maybe:

allTests = catMaybes [tc1, tc2, tc3, tc4, tc5] 

Voici le résultat de l'exécution allTests:

*Q46376632> allTests 
["shouldnt have been 1", 
"shouldnt have been 2", 
"shouldnt have been 11", 
"shouldnt have been 77"] 

Si vous ne pouvez pas modifier la fonction que vous testez, vous pouvez essayer quelque chose comme ce qui suit, mais ce n'est pas très élégant:

tc1 = catch (print $ test 1) (\err -> print (err :: SomeException)) 
tc2 = catch (print $ test 2) (\err -> print (err :: SomeException)) 
tc3 = catch (print $ test 11) (\err -> print (err :: SomeException)) 
tc4 = catch (print $ test 77) (\err -> print (err :: SomeException)) 
tc5 = catch (print $ test 5) (\err -> print (err :: SomeException)) 

allTests = sequence_ [tc1, tc2, tc3, tc4, tc5] 

Lors de l'exécution, vous obtenez une sortie comme ceci:

*Q46376632> allTests 
shouldnt have been 1 
CallStack (from HasCallStack): 
    error, called at 46376632.hs:14:10 in main:Q46376632 
shouldnt have been 2 
CallStack (from HasCallStack): 
    error, called at 46376632.hs:15:10 in main:Q46376632 
shouldnt have been 11 
CallStack (from HasCallStack): 
    error, called at 46376632.hs:16:11 in main:Q46376632 
shouldnt have been 77 
CallStack (from HasCallStack): 
    error, called at 46376632.hs:17:11 in main:Q46376632 
True 

À ce stade, vous seriez probablement mieux d'utiliser un cadre de contrôle approprié.

+0

Salut merci. J'aime le bloc de code avec 'tc1 = catch (imprimer $ test 1) (\ err -> imprimer (err :: SomeException))' '...' – Jhoy

+0

J'ai une question, si j'ai une liste ie 'allTests = [tc1, tc2, tc3, tc4] 'Puis-je utiliser quelque chose de similaire sur cette liste afin de réduire le code en double? – Jhoy

+0

@Jhoy Tout d'abord, sachez que ce code 'catch' n'est pas élégant, ni même approprié, code Haskell. Cela dit, vous pouvez utiliser 'map' (ou' fmap') sur '[a]'. –