Suche…


Grundlegende Syntax

Datensätze sind eine Erweiterung des summengebraischen data , mit denen Felder benannt werden können:

data StandardType = StandardType String Int Bool --standard way to create a sum type

data RecordType = RecordType { -- the same sum type with record syntax
    aString :: String
  , aNumber :: Int
  , isTrue  :: Bool
  }

Die Feldnamen können dann verwendet werden, um das benannte Feld aus dem Datensatz zu holen

> let r = RecordType {aString = "Foobar", aNumber= 42, isTrue = True}
> :t r
  r :: RecordType
> :t aString
  aString :: RecordType -> String
> aString r
  "Foobar"

Datensätze können mit einem Muster verglichen werden

case r of
  RecordType{aNumber = x, aString=str} -> ... -- x = 42, str = "Foobar"

Beachten Sie, dass nicht alle Felder benannt werden müssen

Datensätze werden durch Benennung ihrer Felder erstellt, können aber auch als gewöhnliche Summenarten erstellt werden (oft nützlich, wenn die Anzahl der Felder klein ist und sich wahrscheinlich nicht ändert)

r  = RecordType {aString = "Foobar", aNumber= 42, isTrue = True}
r' = RecordType  "Foobar" 42 True

Wenn ein Datensatz ohne ein benanntes Feld erstellt wird, gibt der Compiler eine Warnung aus und der resultierende Wert ist undefined .

> let r = RecordType {aString = "Foobar", aNumber= 42}
  <interactive>:1:9: Warning:
     Fields of RecordType not initialized: isTrue
> isTrue r
  Error 'undefined'

Ein Feld eines Datensatzes kann durch Setzen seines Werts aktualisiert werden. Nicht erwähnte Felder ändern sich nicht.

> let r = RecordType {aString = "Foobar", aNumber= 42, isTrue = True}
> let r' = r{aNumber=117}
    -- r'{aString = "Foobar", aNumber= 117, isTrue = True}

Es ist oft nützlich, Objektive für komplizierte Aufnahmetypen zu erstellen.

Datensätze beim Ändern von Feldwerten kopieren

Angenommen, Sie haben diesen Typ:

data Person = Person { name :: String, age:: Int } deriving (Show, Eq)

und zwei Werte:

alex = Person { name = "Alex", age = 21 }
jenny = Person { name = "Jenny", age = 36 }

Ein neuer Wert vom Typ Person kann durch Kopieren von alex , wobei die zu ändernden Werte angegeben werden

anotherAlex = alex { age = 31 }

Die Werte von alex und anotherAlex jetzt:

Person {name = "Alex", age = 21}

Person {name = "Alex", age = 31}

Datensätze mit newtype

Record-Syntax kann mit newtype mit der Einschränkung, dass es genau einen Konstruktor mit genau einem Feld gibt. Der Vorteil hierbei ist die automatische Erstellung einer Funktion zum Entpacken des neuen Typs. Diese Felder werden oft mit run für Monaden, get für Monoids und un für andere Typen benannt.

newtype State s a = State { runState :: s -> (s, a) }

newtype Product a = Product { getProduct :: a }

newtype Fancy = Fancy { unfancy :: String } 
  -- a fancy string that wants to avoid concatenation with ordinary strings

Es ist wichtig zu wissen, dass die Datensatzsyntax normalerweise niemals zur Bildung von Werten verwendet wird und der Feldname ausschließlich zum Entpacken verwendet wird

getProduct $ mconcat [Product 7, Product 9, Product 12]
-- > 756

RecordWildCards

{-# LANGUAGE RecordWildCards #-}

data Client = Client { firstName     :: String
                     , lastName      :: String
                     , clientID      :: String 
                     } deriving (Show)

printClientName :: Client -> IO ()
printClientName Client{..} = do
    putStrLn firstName
    putStrLn lastName
    putStrLn clientID

Der Muster- Client{..} bezieht alle Felder des Konstruktor- Client und entspricht dem Muster

Client{ firstName = firstName, lastName = lastName, clientID = clientID }

Es kann auch mit anderen Field Matchern kombiniert werden:

Client { firstName = "Joe", .. }

Das ist äquivalent zu

Client{ firstName = "Joe", lastName = lastName, clientID = clientID }

Definieren eines Datentyps mit Feldbeschriftungen

Es ist möglich, einen Datentyp mit Feldbeschriftungen zu definieren.

data Person = Person { age :: Int, name :: String }

Diese Definition unterscheidet sich von einer normalen Datensatzdefinition, da sie auch * Record Accessors definiert, mit denen auf Teile eines Datentyps zugegriffen werden kann.

In diesem Beispiel werden zwei Record Accessors definiert, age und name , mit denen wir auf die Felder age und name zugreifen können.

age :: Person -> Int
name :: Person -> String

Record Accessoren sind nur Haskell-Funktionen, die automatisch vom Compiler generiert werden. Als solche werden sie wie gewöhnliche Haskell-Funktionen verwendet.

Durch die Benennung von Feldern können wir die Feldbezeichnungen auch in einer Reihe anderer Kontexte verwenden, um den Code lesbarer zu machen.

Musterabgleich

lowerCaseName :: Person -> String
lowerCaseName (Person { name = x }) = map toLower x

Wir können den Wert, der sich an der Position der relevanten Feldbeschriftung befindet, binden, während der Mustervergleich mit einem neuen Wert (in diesem Fall x ) erfolgt, der auf der RHS einer Definition verwendet werden kann.

Musterabgleich mit NamedFieldPuns

lowerCaseName :: Person -> String
lowerCaseName (Person { name }) = map toLower name

Die NamedFieldPuns Erweiterung ermöglicht es uns stattdessen, nur die NamedFieldPuns anzugeben, mit der wir übereinstimmen möchten. Dieser Name wird dann auf der rechten Seite einer Definition NamedFieldPuns sodass der Bezug auf name auf den Wert und nicht auf den Datensatz-Accessor verweist.

Musterabgleich mit RecordWildcards

lowerCaseName :: Person -> String
lowerCaseName (Person { .. }) = map toLower name

Beim Abgleich mit RecordWildCards werden alle RecordWildCards in den Geltungsbereich gebracht. (In diesem speziellen Beispiel name und age )

Diese Erweiterung ist leicht umstritten, da nicht klar ist, wie Werte in den Geltungsbereich einbezogen werden, wenn Sie sich der Definition von Person nicht sicher sind.

Updates aufzeichnen

setName :: String -> Person -> Person
setName newName person = person { name = newName }

Es gibt auch eine spezielle Syntax für die Aktualisierung von Datentypen mit Feldbezeichnungen.



Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow