Pergunta

Quando o tipo X é definido como:

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

e eu quero o Int dentro de um valor X, se houver, caso contrário, zero.

returnInt :: X -> Int

Como posso determinar que tipo de X o argumento para returnInt é?

Foi útil?

Solução

Só para esclarecer um ponto aqui, deixe-me reescrever o seu tipo de dados a ambiguidades evitar no significado de X:

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

Nesta definição não há nenhum X, I e tipo B. X, I e B são construtores que criam um valor do tipo Sometype. Observe o que acontece quando você perguntar ghci Qual é o tipo de qualquer valor construído com esses construtores do tipo:

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

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

Eles pertencem ao mesmo tipo !!

Assim como você pode usar X, I e B para a construção de tipos, você pode usar a correspondência de padrões para desconstruir o tipo, como feito nas outras respostas acima:

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

Basta lembrar que a correspondência de padrões ocorre em ordem:. Se o valor corresponde ao padrão em alguma linha, os padrões em linhas abaixo que não vai ser executado

Note que quando você define o seu tipo de como você fez, usando o que é chamado de Registro Syntax (basta olhar aqui: http://en.wikibooks.org/wiki/Haskell/More_on_datatypes ), você tem funções como a de graça !!

Tente olhar sobre o tipo de myInt, por exemplo:

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

e olha o que esta função fazer:

*Main> myInt (I 5)
5

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

Este é exatamente o comportamento de returnInt acima definido. A mensagem de erro estranha apenas diz que a função não sabem como lidar com um membro do tipo SomeType que não corresponde (I x).

Se você definir o seu tipo usando a sintaxe mais comuns:

data SomeType2 = X String | I Int | B Bool

então você perder essas funções de gravação agradáveis.

As mensagens de erro terminar a execução do programa. Isso às vezes é chato. Se você precisa de um comportamento mais seguro para as suas funções de resposta de GBacon é apenas a maneira de fazê-lo. Saiba mais sobre o tipo Maybe a e usá-lo para lidar com este tipo de computação que necessidade de retornar algum valor ou retorno nada (tente o seguinte: http://en.wikibooks.org/wiki/Haskell/Hierarchical_libraries/Maybe ).

Outras dicas

Use a correspondência de padrão.

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

Use uma definição mais flexível para todos os valores X possíveis:

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

Então você pode usar maybe para o particular inadimplente você quer-0 pode ser um valor válido (isso é conhecido como o problema semipredicate ):

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

Em contraste, funções parciais de risco exceções de tempo de execução:

*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

Se você está sentindo realmente comedor de rãs, você poderia usar MonadPlus

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

para ganhar ainda mais flexibilidade:

*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]

Dada uma função como esta:

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

... o tipo de x é sempre X. O que importa é se x usa o construtor X, I ou tipo B.

Use a correspondência de padrões de dizer a diferença:

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"
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top