2010-12-06 8 views
2

je besoin d'une fonction qui fonctionne comme:Comment déclarer la fonction (type malentendu peut-être)

some :: (Int, Maybe Int) -> Int 
some a b 
    | b == Nothing = 0 
    | otherwise = a + b 

Cas d'utilisation:

some (2,Just 1) 
some (3,Nothing) 
map some [(2, Just 1), (3,Nothing)] 

Mais mon code lever l'erreur:

The equation(s) for `some' have two arguments, 
but its type `(Int, Maybe Int) -> Int' has only one 

Je ne le comprends pas.

Merci d'avance.

+4

'some = uncurry $ peut-être 0. (+) ' – Dario

+0

Vous pourriez être intéressé par la question plus générique de la façon de travailler avec un type' Maybe a', [répondu ici] (http: // stackoverflow.com/questions/3375483/opération-sur-un-retour-d'-un-peut-que-contient-juste/3375712 # 3375712). –

Répondre

10

Lorsque vous écrivez

foo x y = ... 

C'est la notation pour une fonction cari, avec un type comme:

foo :: a -> b -> c 

Vous avez déclaré votre fonction d'attendre un tuple, vous devez donc écrire il:

some :: (Int, Maybe Int) -> Int 
some (x, y) = ... 

Mais la convention de Haskell est usu allié à prendre des arguments dans l'ancienne forme curry. Voir des fonctions prendre des tuples comme arguments est très rare.

Pour l'autre partie de votre question, vous voudrez probablement l'exprimer avec un motif. Vous pourriez dire:

foo :: Maybe Int -> Int 
foo Nothing = 0 
foo (Just x) = x + 1 

Généraliser cela à la question OP est laissé comme un exercice pour le lecteur.

+1

Merci. La correspondance des motifs est ce dont j'ai besoin. – demas

+0

Plutôt que de faire correspondre un motif, je l'écrirais probablement 'un un b = deMaybe 0 (fmap (+ a) b)', et le libèrerais de 'a a = fromMaybe 0. fmap (+ a) '. –

+2

@John, pensez-vous qu'il est utile de suggérer l'utilisation de Functors et d'un style sans point à quelqu'un qui ne comprend pas encore le curry et le pattern-matching? – adamse

7

Votre erreur ne provient pas d'un malentendu de Maybe: La signature de type de some indique qu'il faut une paire (Int, Maybe Int), alors que dans votre définition vous lui fournissez deux arguments. La définition devrait donc commencer par some (a,b) pour correspondre à la signature de type.

Une façon de résoudre le problème (qui est aussi un peu plus idiomatiques et utilise pattern matching) est:

some :: (Int, Maybe Int) -> Int 
some (a, Nothing) = a 
some (a, Just b) = a + b 

Il est également intéressant de noter que si vous avez une très bonne raison d'utiliser un tuple en entrée , vous ne devriez probablement pas le faire. Si votre signature était à la place some :: Int -> Maybe Int -> Int, vous auriez une fonction de deux arguments, qui peut être curried. Ensuite, vous écririez quelque chose comme

some :: Int -> Maybe Int -> Int 
some a Nothing = a 
some a (Just b) = a + b 

En outre, vous voudrez peut-être ajouter la généralisation immédiate suivante: Tous les types Num sont additifs, vous pourriez donc faire aswell

some :: (Num n) => n -> Maybe n -> n 
some a Nothing = a 
some a (Just b) = a + b 

(je l'ai violé la pratique courante d'utiliser a, b, c ... pour les variables de type afin de ne pas confondre l'OP puisqu'il lie a et b aux arguments de some).