Question

Si le type est défini comme X:

data X = 
    X { sVal :: String } |
    I { iVal :: Int } |
    B { bVal :: Bool }

et je veux la Int l'intérieur d'une valeur X, s'il y a un, sinon nul.

returnInt :: X -> Int

Comment puis-je déterminer quel type de X l'argument est returnInt?

Était-ce utile?

La solution

Juste pour clarifier un point ici, permettez-moi de réécrire votre type de données pour éviter les ambiguïtés dans la signification de X:

data SomeType = X { myString :: String} | I {myInt :: Int} | B {myBool :: Bool}

Dans cette définition, il n'y a pas X, I et types B. X, I et B sont constructeurs qui créent une valeur de type Sometype. Notez ce qui se passe lorsque vous demandez ghci quel est le type d'une valeur construite avec les constructeurs de type:

*Main> :t (I 5)
(I 5) :: Sometype 

*Main> :t (B False)
(B False) :: Sometype

Ils appartiennent au même type !!

Comme vous pouvez utiliser X, I et B pour construire des types, comme fait dans les autres réponses ci-dessus, vous pouvez utiliser modèle correspondant à déconstruire le type,:

returnInt :: SomeType -> Int 
returnInt (I x) = x        -- if the pattern matches (I x) then return x
returnInt _  = error "I need an integer value, you moron"  -- throw an error otherwise

Rappelez-vous simplement que la correspondance de modèle se produit dans l'ordre:. Si la valeur correspond au modèle dans une ligne, les modèles dans les lignes ci-dessous qui ne seront pas exécutées

Notez que lorsque vous définissez votre type comme vous l'avez fait, en utilisant ce qu'on appelle enregistrement de syntaxe (il suffit de regarder ici: http://en.wikibooks.org/wiki/Haskell/More_on_datatypes ), vous avez des fonctions comme cela gratuitement !!

Essayez de regarder le type de myInt, par exemple:

*Main> :t myInt
myInt :: SomeType -> Int

Et regardez ce que cette fonction ne:

*Main> myInt (I 5)
5

*Main> myInt (B False)
*** Exception: No match in record selector Main.myInt

Ceci est exactement le comportement de returnInt défini ci-dessus. L'étrange message d'erreur vous indique simplement que la fonction ne sais pas comment faire face à un membre du type UnType qui ne correspond pas à (I x).

Si vous définissez votre type en utilisant la syntaxe plus commune:

data SomeType2 = X String | I Int | B Bool

vous perdez ces belles fonctions d'enregistrement.

Les messages d'erreur terminent l'exécution du programme. Cela est parfois gênant. Si vous avez besoin un comportement plus sûr pour vos fonctions de réponse de GBacon est juste la façon de le faire. En savoir plus sur le type de Maybe a et l'utiliser pour faire face à ce genre de calcul qui ont besoin de retourner une valeur ou retourner rien (essayez ceci: http://en.wikibooks.org/wiki/Haskell/Hierarchical_libraries/Maybe ).

Autres conseils

Utilisation correspondance de motif.

returnInt :: X -> Int
returnInt (I x) = x
returnInt _     = 0

Utilisez une définition plus souple pour toutes les valeurs possibles X:

returnInt :: X -> Maybe Int
returnInt (I i) = Just i
returnInt _ = Nothing

Ensuite, vous pouvez utiliser maybe pour la vous voulez-0 défaut particulier pourrait être une valeur valide (ce qui est connu comme le semipredicate problème ):

*Main> maybe 0 id (returnInt $ X "")
0
*Main> maybe 0 id (returnInt $ I 123)
123
*Main> maybe (-1) id (returnInt $ X "yo")
-1

En revanche, les exceptions d'exécution de risque fonctions partielles:

*Main> let returnInt (I i) = i
*Main> :t returnInt
returnInt :: X -> Int
*Main> returnInt (B True)
*** Exception: <interactive>:1:4-22: Non-exhaustive patterns in function returnInt

Si vous vous sentez vraiment froggy, vous pouvez utiliser MonadPlus

returnInt :: (MonadPlus m) => X -> m Int
returnInt (I i) = return i
returnInt _ = mzero

pour gagner encore plus de flexibilité:

*Main> maybe 0 id (returnInt $ X "")
0
*Main> maybe 0 id (returnInt $ I 123)
123
*Main> returnInt (I 123) `mplus` returnInt (I 456) :: [Int]
[123,456]

Étant donné une fonction comme ceci:

returnInt :: X -> Int
returnInt x = {- some integer -}

... le type de x est toujours X. Qu'est-ce que vous vous souciez est de savoir si x utilise le X, I ou constructeur de type B.

Mode d'utilisation correspondant à la différence:

returnInt :: X -> Int
returnInt (X _) = error "needed an Int, got a String"
returnInt (I { iVal = n }) = n
returnInt (B _) = error "needed an Int, got a Bool"
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top