Die Wahl zwischen Alternativen in einem Haskell algebraischen Datentyp
-
13-09-2019 - |
Frage
Wenn Typ X
ist wie folgt definiert:
data X =
X { sVal :: String } |
I { iVal :: Int } |
B { bVal :: Bool }
und ich möchte die Int
innerhalb eines X
Wert, wenn es einen gibt, sonst Null.
returnInt :: X -> Int
Wie kann ich, welche Art von X
bestimmen das Argument returnInt
ist?
Lösung
Nur einen Punkt hier zu klären, lassen Sie mich Ihren Datentyp umschreiben Zweideutigkeiten in der Bedeutung von X zu vermeiden:
data SomeType = X { myString :: String} | I {myInt :: Int} | B {myBool :: Bool}
In dieser Definition gibt es keine X, I und B-Typen. X, I und B sind Konstruktoren, die einen Wert vom Typ Sometype
erstellen. Beachten Sie, was passiert, wenn Sie GHCI fragen, was die Art von Wert mit diesen Typkonstruktoren aufgebaut ist:
*Main> :t (I 5)
(I 5) :: Sometype
*Main> :t (B False)
(B False) :: Sometype
Sie gehören zur gleichen Art !!
Wie Sie X verwenden können, I und B-Typen zu konstruieren, können Sie Muster wie in den anderen Antworten getan verwenden Anpassung der Art dekonstruieren, oben:
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
Bitte beachten Sie, dass Mustervergleich erfolgt, um:., Wenn der Wert das Muster in irgendeiner Zeile übereinstimmt, werden die Muster in den Zeilen unter dem nicht ausgeführt werden
Beachten Sie, dass, wenn Sie Ihre Art definieren wie Sie haben, mit was Rekord Syntax aufgerufen wird (nur hier: http://en.wikibooks.org/wiki/Haskell/More_on_datatypes ), haben Sie Funktionen wie das kostenlos !!
Versuchen Sie, auf die Art der myInt, zum Beispiel suchen:
*Main> :t myInt
myInt :: SomeType -> Int
Und schauen, was diese Funktion tun:
*Main> myInt (I 5)
5
*Main> myInt (B False)
*** Exception: No match in record selector Main.myInt
Das ist genau das Verhalten von returnInt
oben definiert ist. Die seltsame Fehlermeldung sagt Ihnen, nur, dass die Funktion nicht wissen, wie mit einem Mitglied des Typ Sometype beschäftigen, die nicht (I x)
entsprechen.
Wenn Sie Ihre Art mit der häufigeren Syntax definieren:
data SomeType2 = X String | I Int | B Bool
dann verlieren Sie die schönen Aufnahmefunktionen.
Die Fehlermeldungen, die Ausführung des Programms beenden. Das ist manchmal ärgerlich. Wenn Sie sicherer Verhalten für Ihre Funktionen Antwort GBacon die brauchen, ist nur die Art und Weise, es zu tun. Erfahren Sie mehr über die Maybe a
Typ und verwenden Sie es mit dieser Art von Berechnung fertig zu werden, die einen Wert zurückgeben müssen oder zurückgeben nichts (versuchen Sie dies: http://en.wikibooks.org/wiki/Haskell/Hierarchical_libraries/Maybe ).
Andere Tipps
Mit Mustervergleich.
returnInt :: X -> Int
returnInt (I x) = x
returnInt _ = 0
Verwenden Sie eine flexiblere Definition für alle möglichen X
Werte:
returnInt :: X -> Maybe Int
returnInt (I i) = Just i
returnInt _ = Nothing
Dann können Sie verwenden maybe
für die jeweilige säumige Sie wollen-0 könnte einen gültigen Wert sein (dies ist als der semipredicate Problem ):
*Main> maybe 0 id (returnInt $ X "")
0
*Main> maybe 0 id (returnInt $ I 123)
123
*Main> maybe (-1) id (returnInt $ X "yo")
-1
Im Gegensatz dazu Teilfunktionen Risikolaufzeit Ausnahmen:
*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
Wenn Sie wirklich Froggy Gefühl sind, können Sie MonadPlus
verwenden
returnInt :: (MonadPlus m) => X -> m Int
returnInt (I i) = return i
returnInt _ = mzero
gewinnen noch mehr Flexibilität:
*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]
Bei einer Funktion wie folgt aus:
returnInt :: X -> Int
returnInt x = {- some integer -}
... die Art der x
immer X
. Was Sie wichtig ist, ob x
verwendet den X
, I
oder B
Typkonstruktor.
Mit Mustervergleich den Unterschied zu erkennen:
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"