2011-05-04 3 views
3

Supposons, par exemple, nous avons la structure de données suivantes:'pattern matching' sur les types typable

data Foo = Bool Bool | Int Int | Double Double 

Maintenant, est-il un moyen plus facile de le faire:

foo :: Typeable a => a -> Foo 
foo x = maybe (error "i dunno") id $ 
    liftM Bool (cast x) `mplus` 
    liftM Int (cast x) `mplus` 
    liftM Double (cast x) 

Quelqu'un at-il pensé de faire une syntaxe pour la correspondance de modèle sur Types typables?

Répondre

6

Utilisez typeOf et gardes:

foo x 
    | tx == typeOf "str" = "string" 
    | tx == typeOf True = "bool" 
    | otherwise   = "i dunno" 
    where tx = typeOf x 
+2

Je pense que cela est une bonne approche. Un point mineur est que typeOf "str" ​​ne fonctionnera pas bien en présence de OverloadedStrings, ce qui est devenu plus commun ces jours-ci. –

+0

Il existe un problème similaire avec les littéraux numériques. Il ne s'adapte pas non plus aux situations où vous n'avez pas de constructeur pour le type de données/ils ne sont pas purs. Vous finiriez avec '(undefined :: Foo)' avant trop longtemps, ce qui est moche. Pour cette raison, je n'aime pas cette solution. – Tener

+0

Typecase devrait être un peu minable. Cela nous rappelle de retourner à la programmation avec de vrais types et d'arrêter de jouer avec toute cette dureté d'exécution. – sclv

3

Cette version ne se limite pas à Bool, Int ou Double, mais un String SORT comme [Char].

foo :: Typeable a => a -> String 
foo = show . typeOf 
+1

... ce qui est raisonnable, puisque 'String' est juste un alias de type pour [[Char]'. – hammar

4

Vous pouvez utiliser des motifs de vue ici, ils sont très pratiques.

{-# LANGUAGE ViewPatterns #-} 

import Data.Data 

data Foo = Bool Bool | Int Int | Double Double 
     deriving (Show) 

foo :: Typeable a => a -> Foo 
foo (cast -> Just x) = Int x 
foo (cast -> Just x) = Bool x 
foo (cast -> Just x) = Double x 
foo _ = error "i dunno" 

Résultats:

 
*Main> :l foo_typeable.hs 
[1 of 1] Compiling Main    (foo_typeable.hs, interpreted) 
Ok, modules loaded: Main. 
*Main> foo "123" 
*** Exception: i dunno 
*Main> foo 1 
*** Exception: i dunno 
*Main> foo (1 :: Int) 
Int 1 
*Main> foo (1 :: Integer) 
*** Exception: i dunno 
*Main> foo (1 :: Double) 
Double 1.0 
+0

C'est une solution plutôt sympa! –