Domanda

Quando il tipo X è definito come:

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

e voglio il Int all'interno di un valore di X, se ce n'è uno, altrimenti zero.

returnInt :: X -> Int

Come è possibile determinare quale tipo di X l'argomento per returnInt è?

È stato utile?

Soluzione

Giusto per chiarire un punto qui, mi permetta di riscrivere il tipo di dati per evitare ambiguità nel significato di X:

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

In questa definizione non ci sono X, I e tipo B. X, I e B sono costruttori che creano un valore di tipo Sometype. Nota cosa succede quando si chiede ghci qual è il tipo di qualsiasi valore costruito con quei costruttori di tipo:

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

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

Appartengono allo stesso tipo !!

Così come è possibile usare X, I e B per la costruzione di tipi, è possibile utilizzare il pattern matching per decostruire il tipo, come fatto nelle altre risposte di cui sopra:

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 ricordare che il pattern matching si verifica in ordine:. Se il valore corrisponde al modello in qualche linea, non saranno eseguiti i modelli a righe sotto che

Si noti che quando si definisce il tipo di come avete fatto, utilizzando quello che viene chiamato Record di sintassi (solo guardare qui: http://en.wikibooks.org/wiki/Haskell/More_on_datatypes ), hai le funzioni del genere gratis !!

Prova a guardare il tipo di myInt, ad esempio:

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

E guarda che questa funzione fare:

*Main> myInt (I 5)
5

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

Questo è esattamente il comportamento di returnInt sopra definito. Il messaggio di errore strano solo ti dice che la funzione non sanno come trattare con un membro del SomeType tipo che non corrisponde (I x).

Se si definisce il tipo utilizzando la sintassi più comuni:

data SomeType2 = X String | I Int | B Bool

allora perdi quelle belle funzioni di registrazione.

I messaggi di errore terminano l'esecuzione del programma. Questo è fastidioso a volte. Se avete bisogno di un comportamento più sicuro per le funzioni risposta di GBacon è solo il modo per farlo. Conoscere il tipo Maybe a e utilizzarlo per far fronte a questo tipo di calcolo, che hanno bisogno di tornare un valore o restituire nulla (provate questo: http://en.wikibooks.org/wiki/Haskell/Hierarchical_libraries/Maybe ).

Altri suggerimenti

Usa pattern matching.

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

Con una definizione più flessibile per tutti i possibili valori X:

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

Quindi è possibile utilizzare maybe per l'inadempiente particolare che si desidera-0 potrebbe essere un valore valido (questo è noto come il semipredicate problema ):

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

Al contrario, funzioni parziali rischio runtime eccezioni:

*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 ti senti veramente Froggy, si potrebbe usare MonadPlus

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

per ottenere una flessibilità ancora maggiore:

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

Data una funzione come questa:

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

... il tipo di x è sempre X. Quello che interessa è se x utilizza il X, I o B tipo di costruzione.

Usa pattern matching a dire la differenza:

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"
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top