##Mit data eigene Typen definieren
data MyType = MyConstructor Int String
deriving(Show)
ghci>MyConstructor 1 "me"
ghci>:type it
it :: MyType
##TypeSynonyms
type MyId = Int
##Algebraic Types
data MyType = MyFirstConstructor | MySecondConstructor
##PatternMatching
Um aus einem vordefinierten Datentyp oder Tupel einzelne Werte zu extrahieren
kann mit einer entsprechenden Funktionsdefinition der Typus 'dekonstruiert' werden:
getID :: MyType -> Int
getID (MyConstructor id _) = id
getName :: MyType -> String
getName (MyConstructor _ name) = name
Da das Wunschdatum von seiner Position im Datentyp abhängt, müssen die Variablen
entsprechend der Reihenfolge im Constructor definiert werden. Sollten bestimmte
Variablen nicht interessieren, kann der Platzhalter _ auch mehrfach benutzt werden,
um Variablen zu ignorieren.
Mit dem : lassen sich Listen im Funktionsaufruf dekonstruieren:
mySum [] = 0
mySum (x:xs) = x + mySum xs
##Record Syntax
Die Record Syntax ist eine convienience-Schreibweise, mit der neben der
Typen-Deklaration auch automatisch die Getter der einzelnen Typ-Komponenten erstellt werden
können:
data MyOtherType = MyOtherType {
myId :: Integer
, name :: String
} deriving (Show)
ghci> name (MyOtherType 5 "my name")
"my name"
Hier sei erwähnt, dass die Namensräume für Typen und für Funktionen getrennt sind, so dass es nicht nur kein Problem darstellt, den Konstruktor zu nennen wie den Typen, es ist obendrein auch gängige Praxis in der Haskell-Welt.
##Parametrized Types
Parametrisierte Typen legen ihre Parameter nicht auf einen Basistypen fest sondern können
ähnlich wie Listen und Tupel unterschiedliche Datentypen aufnehmen.
##Was will uns der
##Compiler damit sagen? I
ghci> :load mySum.hs
[1 of 1] Compiling Main ( mySum.hs, interpreted )
mySum.hs:13:20:
Could not deduce (a ~ ([Integer] -> Integer))
from the context (Num a)
bound by the type signature for mySum :: Num a => [a] -> a
at mySum.hs:11:10-26
`a' is a rigid type variable bound by
the type signature for mySum :: Num a => [a] -> a
at myLength.hs:11:10
In the second argument of `(+)', namely `mySum'
In the expression: n + mySum
In an equation for `mySum': mySum (n : ns) = n + mySum
Failed, modules loaded: none.
ghci>
##Was will uns der
##Compiler damit sagen? I
mySum :: Num a => [a] -> a
mySum [] = 0
mySum (n:ns) = n + mySum
mySum wird rekursiv ohne Parameter aufgerufen
mySum wird rekursiv ohne Parameter aufgerufen
##Was will uns der
##Compiler damit sagen? II
ghci> :load myMean.hs
[1 of 1] Compiling Main ( myMean.hs, interpreted )
myMean.hs:19:13:
Could not deduce (Integral a) arising from a use of `fromIntegral'
from the context (Num a)
bound by the type signature for myMean :: Num a => [a] -> Double
at myMean.hs:18:11-32
Possible fix:
add (Integral a) to the context of
the type signature for myMean :: Num a => [a] -> Double
In the first argument of `(/)', namely `fromIntegral (sum (ns))'
In the expression:
fromIntegral (sum (ns)) / fromIntegral (length (ns))
In an equation for `myMean':
myMean ns = fromIntegral (sum (ns)) / fromIntegral (length (ns))
Failed, modules loaded: none.
ghci>
##Was will uns der
##Compiler damit sagen? II
myMean :: Num a => [a] -> Double
myMean ns = fromIntegral(sum(ns))/fromIntegral(length(ns))
Der Compiler erwartet eine andere Typensignatur:
Der Compiler erwartet eine andere Typensignatur:
myMean :: (Fractional a, Integral a1) => [a1] -> a
Warum? Was Stimmt an meiner Signatur nicht? Mit der Signatur des Compilers
erhalte ich nicht dass was ich will, nämlich einen Durchschnitt einer Liste
unabhängig von ihrem Typ, so lange ihr Typ von Num abgeleitet ist.
##Was will uns der
##Compiler damit sagen? III
ghci> :load myReverse.hs
[1 of 1] Compiling Main ( myReverse.hs, interpreted )
Ok, modules loaded: Main.
ghci> myReverse "doof"
<interactive>:13:11:
Couldn't match type `Char' with `[a0]'
Expected type: <a class="internal" href="/wiki/lernfp/a0">a0</a>
Actual type: [Char]
In the first argument of `myReverse', namely `"doof"'
In the expression: myReverse "doof"
In an equation for `it': it = myReverse "doof"
ghci>
##Was will uns der
##Compiler damit sagen? III
myReverse [] = []
myReverse (x:xs) = myReverse(xs) ++ x
Hier wurde übersehen, dass der ++-Operator als zweiten Parameter
Hier wurde übersehen, dass der ++-Operator als zweiten Parameter
eine Liste und keinen einzelnen Wert erwartet.
##Was will uns der
##Compiler damit sagen? IV
ghci> :load takeHalf.hs
[1 of 1] Compiling Main ( takeHalf.hs, interpreted )
takeHalf.hs:7:24:
Couldn't match expected type `a1 -> Int' with actual type `Int'
The function `length' is applied to two arguments,
but its type `[a0] -> Int' has only one
In the first argument of `div', namely `(length (xs) 2)'
In the first argument of `take', namely `(div (length (xs) 2) xs)'
takeHalf.hs:7:38:
Couldn't match expected type `Int' with actual type `[a0]'
In the second argument of `div', namely `xs'
In the first argument of `take', namely `(div (length (xs) 2) xs)'
In the expression: take (div (length (xs) 2) xs)
Failed, modules loaded: none.
ghci>
##Was will uns der
##Compiler damit sagen? IV
Das ist falsch
takeHalf xs = take(div(length(xs) 2) xs)
Das ist richtig:
takeHalf xs = (take (div (length xs) 2) xs)
##Und warum ist das so?
Prelude> let value = length [1,2,3]
Prelude> :type value
value :: Int
Prelude> let notNum = fromIntegral value
Prelude> :type notNum
notNum :: Integer
Prelude>
#Thank you