Suche…


Syntax

  1. leerer Listenkonstruktor

    [] :: [a]

  2. Nicht leerer Listenkonstruktor

    (:) :: a -> [a] -> [a]

  3. head - gibt den ersten Wert einer Liste zurück

    head :: [a] -> a

  4. last - gibt den letzten Wert einer Liste zurück

    last :: [a] -> a

  5. tail - gibt eine Liste ohne den ersten Eintrag zurück

    tail :: [a] -> [a]

  6. init - gibt eine Liste ohne den letzten Eintrag zurück

    init :: [a] -> [a]

  7. xs !! i - gibt das Element an einem Index i in Liste xs zurück

    (!!) :: Int -> [a] -> a

  8. take n xs - neue Liste mit n ersten Elementen der Liste xs zurückgeben

    take :: Int -> [a] -> [a]

  9. map :: (a -> b) -> [a] -> [b]

  10. filter :: (a -> Bool) -> [a] -> [a]

  11. (++) :: [a] -> [a]

  12. concat :: [[a]] -> [a]

Bemerkungen

  1. Der Typ [a] entspricht [] a .
  2. [] die leere Liste.
  3. [] in einer Funktionsdefinition LHS, zB f [] = ... , ist das leere Listenmuster.
  4. x:xs eine Liste, in der der Liste xs ein Element x vorangestellt wird
  5. f (x:xs) = ... ist eine Musterübereinstimmung für eine nicht leere Liste, wobei x der Kopf und xs der Schwanz ist.
  6. f (a:b:cs) = ... und f (a:(b:cs)) = ... sind gleich. Sie sind eine Musterübereinstimmung für eine Liste von mindestens zwei Elementen, wobei das erste Element a , das zweite Element b ist und der Rest der Liste cs .
  7. f ((a:as):bs) = ... ist NICHT dasselbe wie f (a:(as:bs)) = ... Ersteres ist eine Musterübereinstimmung für eine nicht leere Liste von Listen, wobei a der Kopf des Kopfes ist, as wie der Schwanz des Kopfes, und bs der Schwanz ist.
  8. f (x:[]) = ... und f [x] = ... sind gleich. Sie sind eine Musterübereinstimmung für eine Liste genau eines Elements.
  9. f (a:b:[]) = ... und f [a,b] = ... sind gleich. Sie sind eine Musterübereinstimmung für eine Liste von genau zwei Elementen.
  10. f [a:b] = ... ist eine Musterübereinstimmung für eine Liste genau eines Elements, bei dem das Element auch eine Liste ist. a ist der Kopf des Elements und b ist der Schwanz des Elements.
  11. [a,b,c] ist dasselbe wie (a:b:c:[]) . Die Standardlistennotation ist nur syntaktischer Zucker für die Konstruktoren (:) und [] .
  12. Sie können all@(x:y:ys) verwenden, um auf die gesamte Liste als all (oder einen beliebigen anderen Namen all@(x:y:ys) zu verweisen, anstatt sie (x:y:ys) erneut zu wiederholen.

List Literals

emptyList     = []

singletonList = [0]               -- = 0 : []

listOfNums    = [1, 2, 3]         -- = 1 : 2 : [3]

listOfStrings = ["A", "B", "C"]

List Verkettung

listA      = [1, 2, 3]

listB      = [4, 5, 6]

listAThenB = listA ++ listB       -- [1, 2, 3, 4, 5, 6]

(++) xs     [] = xs
(++) []     ys = ys
(++) (x:xs) ys = x : (xs ++ ys)

Listen Sie die Grundlagen auf

Der Typkonstruktor für Listen im Haskell-Prelude ist [] . Die Typdeklaration für eine Liste, die Werte des Typs Int wird wie folgt geschrieben:

xs :: [Int]    -- or equivalently, but less conveniently,
xs :: [] Int

Listen in Haskell sind homogene Sequenzen , dh alle Elemente müssen vom gleichen Typ sein. Im Gegensatz zu Tupeln ist der Listentyp nicht von der Länge betroffen:

[1,2,3]   :: [Int]
[1,2,3,4] :: [Int]

Listen werden mit zwei Konstruktoren erstellt :

  • [] eine leere Liste.

  • (:) , ausgesprochen "cons", fügt Elemente einer Liste hinzu. Consing x (ein Wert vom Typ a ) auf xs (eine Liste von Werten des gleichen Typ a ) erzeugt eine neue Liste, dessen Kopf (das erste Element) ist x , und der Schwanz (der Rest der Elemente) ist xs .

Wir können einfache Listen wie folgt definieren:

ys :: [a]
ys = []

xs :: [Int]
xs = 12 : (99 : (37 : []))   
-- or  = 12 : 99 : 37 : []     -- ((:) is right-associative)
-- or  = [12, 99, 37]          -- (syntactic sugar for lists)

Beachten Sie, dass (++) , das zum Erstellen von Listen verwendet werden kann, rekursiv in Form von (:) und [] .

Listen bearbeiten

Um Listen zu verarbeiten, können wir die Übereinstimmungen auf den Konstruktoren des Listentyps einfach kopieren:

listSum :: [Int] -> Int
listSum []          = 0
listSum (x:xs) = x + listSum xs

Wir können mehr Werte abgleichen, indem wir ein ausführlicheres Muster angeben:

sumTwoPer :: [Int] -> Int
sumTwoPer [] = 0
sumTwoPer (x1:x2:xs) = x1 + x2 + sumTwoPer xs
sumTwoPer (x:xs) = x + sumTwoPer xs

Beachten Sie, dass wir im obigen Beispiel eine umfassendere Musterübereinstimmung bereitstellen mussten, um Fälle zu behandeln, in denen eine ungerade Längenliste als Argument angegeben ist.

Das Haskell-Präludium definiert viele eingebaute Ins für die Behandlung von Listen, z. B. map , filter usw. Wenn möglich, sollten Sie diese verwenden, anstatt eigene rekursive Funktionen zu schreiben.

Auf Elemente in Listen zugreifen

Greifen Sie auf das n- te Element einer Liste zu (nullbasiert):

list = [1 .. 10]

firstElement = list !! 0           -- 1

Beachten Sie das !! ist eine Teilfunktion, daher verursachen bestimmte Eingaben Fehler:

list !! (-1)     -- *** Exception: Prelude.!!: negative index  

list !! 1000     -- *** Exception: Prelude.!!: index too large

Es gibt auch Data.List.genericIndex , eine überladene Version von !! , der einen beliebigen Integral als Index akzeptiert.

import Data.List (genericIndex)

list `genericIndex` 4              -- 5

Wenn sie als einfach verknüpfte Listen implementiert werden, benötigen diese Operationen O (n) Zeit. Wenn Sie häufig Elemente von Index zugreifen, ist es wahrscheinlich besser zu nutzen Data.Vector (aus dem Vektor - Paket) oder anderen Datenstrukturen.

Bereiche

Das Erstellen einer Liste von 1 bis 10 ist mit der Bereichsnotation einfach:

[1..10]    -- [1,2,3,4,5,6,7,8,9,10]

Um einen Schritt anzugeben, fügen Sie nach dem Startelement ein Komma und das nächste Element hinzu:

[1,3..10]  -- [1,3,5,7,9]

Beachten Sie, dass Haskell den Schritt immer als arithmetische Differenz zwischen Begriffen annimmt und Sie nicht mehr als die ersten beiden Elemente und die obere Grenze angeben können:

[1,3,5..10] -- error
[1,3,9..20] -- error

Um einen Bereich in absteigender Reihenfolge zu generieren, geben Sie immer den negativen Schritt an:

[5..1]     -- []

[5,4..1]   -- [5,4,3,2,1]

Da Haskell nicht streng ist, werden die Elemente der Liste nur dann ausgewertet, wenn sie benötigt werden. Dies ermöglicht die Verwendung unendlicher Listen. [1..] ist eine unendliche Liste, beginnend mit 1. Diese Liste kann an eine Variable gebunden oder als Funktionsargument übergeben werden:

take 5 [1..]   -- returns [1,2,3,4,5] even though [1..] is infinite

Seien Sie vorsichtig bei der Verwendung von Bereichen mit Fließkommawerten, da Überschreitungen bis zum halben Delta akzeptiert werden, um Rundungsprobleme abzuwenden:

[1.0,1.5..2.4]    -- [1.0,1.5,2.0,2.5] , though 2.5 > 2.4

[1.0,1.1..1.2]    -- [1.0,1.1,1.2000000000000002] , though 1.2000000000000002 > 1.2

Bereiche arbeiten nicht nur mit Zahlen, sondern mit jedem Typ, der die Typklasse Enum implementiert. Bei einigen aufzählbaren Variablen a , b , c die Range-Syntax dem Aufruf dieser Enum Methoden:

[a..]    == enumFrom a
[a..c]   == enumFromTo a c
[a,b..]  == enumFromThen a b
[a,b..c] == enumFromThenTo a b c

Zum Beispiel bei Bool

 [False ..]      -- [False,True]

Beachten Sie das Leerzeichen nach False , um zu verhindern, dass dies als Modulnamenqualifikation analysiert wird (dh False.. würde als . Von einem Modul False analysiert werden).

Grundfunktionen in Listen

head [1..10]       --    1

last [1..20]       --    20

tail [1..5]        --    [2, 3, 4, 5]

init [1..5]        --    [1, 2, 3, 4]

length [1 .. 10]   --    10

reverse [1 .. 10]  --    [10, 9 .. 1]

take 5 [1, 2 .. ]  --    [1, 2, 3, 4, 5]

drop 5 [1 .. 10]   --    [6, 7, 8, 9, 10]

concat [[1,2], [], [4]]   --    [1,2,4]

foldl

So wird die linke Falte implementiert. Beachten Sie, wie die Reihenfolge der Argumente in der Schrittfunktion im Vergleich zu foldr (der rechten Falz) foldr :

foldl :: (b -> a -> b) -> b -> [a] -> b
foldl f acc []     =  acc
foldl f acc (x:xs) =  foldl f (f acc x) xs         -- = foldl f (acc `f` x) xs  

Die linke Falte foldl links. Das ist:

foldl (+) 0 [1, 2, 3]     -- is equivalent to ((0 + 1) + 2) + 3

Der Grund ist, dass foldl folgendermaßen bewertet wird ( foldl den induktiven Schritt von foldl ):

foldl (+) 0 [1, 2, 3]                        --  foldl (+)    0   [ 1,   2,   3 ]
foldl (+) ((+) 0 1) [2, 3]                   --  foldl (+)   (0 + 1)   [ 2,   3 ]
foldl (+) ((+) ((+) 0 1) 2) [3]              --  foldl (+)  ((0 + 1) + 2)   [ 3 ]
foldl (+) ((+) ((+) ((+) 0 1) 2) 3) []       --  foldl (+) (((0 + 1) + 2) + 3) []
((+) ((+) ((+) 0 1) 2) 3)                    --            (((0 + 1) + 2) + 3)

Die letzte Zeile entspricht ((0 + 1) + 2) + 3 . Dies liegt daran, dass (fab) im Allgemeinen dasselbe wie (a `f` b) , und dass ((+) 0 1) im (a `f` b) das gleiche wie (0 + 1) .

foldr

So wird die richtige Falte implementiert:

foldr :: (a -> b -> b) -> b -> [a] -> b
foldr f z []     = z
foldr f z (x:xs) = f x (foldr f z xs)              -- = x `f` foldr f z xs

Die rechte Falte foldr nach rechts. Das ist:

foldr (+) 0 [1, 2, 3]      -- is equivalent to 1 + (2 + (3 + 0))

Der Grund ist, dass foldr folgendermaßen bewertet wird (siehe den induktiven Schritt von foldr ):

foldr (+) 0 [1, 2, 3]                        --          foldr (+) 0  [1,2,3]
(+) 1 (foldr (+) 0 [2, 3])                   -- 1 +        foldr (+) 0  [2,3]
(+) 1 ((+) 2 (foldr (+) 0 [3]))              -- 1 + (2 +     foldr (+) 0  [3])
(+) 1 ((+) 2 ((+) 3 (foldr (+) 0 [])))       -- 1 + (2 + (3 +  foldr (+) 0 []))
(+) 1 ((+) 2 ((+) 3 0))                      -- 1 + (2 + (3 +            0   ))

Die letzte Zeile entspricht 1 + (2 + (3 + 0)) , da ((+) 3 0) dasselbe wie (3 + 0) .

Verwandlung mit "map"

Oft möchten wir den Inhalt einer Sammlung (eine Liste oder etwas Durchlaufbares) konvertieren oder umwandeln. In Haskell benutzen wir die map :

 -- Simple add 1
 map (+ 1) [1,2,3]
 [2,3,4]
 
 map odd [1,2,3]
 [True,False,True]
 
 data Gender = Male | Female deriving Show
 data Person = Person String Gender Int deriving Show

 -- Extract just the age from a list of people
 map (\(Person n g a) -> a) [(Person "Alex" Male 31),(Person "Ellie" Female 29)]
 [31,29]

Filtern mit "Filter"

Gegeben eine Liste:

 li = [1,2,3,4,5]

Wir können eine Liste mit einem Vergleichselement filter :: (a -> Bool) -> [a] -> [a] :

 filter (== 1) li       -- [1]
 
 filter (even) li       -- [2,4]
 
 filter (odd) li        -- [1,3,5]
 
 -- Something slightly more complicated
 comfy i = notTooLarge && isEven
   where 
      notTooLarge = (i + 1) < 5
      isEven = even i
 
 filter comfy li        -- [2]

Natürlich geht es nicht nur um Zahlen:

 data Gender = Male | Female deriving Show
 data Person = Person String Gender Int deriving Show
 
 onlyLadies :: [Person] -> Person
 onlyLadies x = filter isFemale x
   where 
     isFemale (Person _ Female _) = True
     isFemale _ = False
 
 onlyLadies [(Person "Alex" Male 31),(Person "Ellie" Female 29)]
 -- [Person "Ellie" Female 29]

Zippen und Entpacken von Listen

zip nimmt zwei Listen und gibt eine Liste der entsprechenden Paare zurück:

zip []     _      = []
zip _      []     = []
zip (a:as) (b:bs) = (a,b) : zip as bs

> zip [1,3,5] [2,4,6]
> [(1,2),(3,4),(5,6)]

Zwei Listen mit einer Funktion komprimieren:

zipWith f  []     _      = []
zipWith f  _      []     = []
zipWith f  (a:as) (b:bs) = f a b : zipWith f as bs

> zipWith (+) [1,3,5] [2,4,6]
> [3,7,11]

Eine Liste entpacken:

unzip = foldr (\(a,b) ~(as,bs) -> (a:as,b:bs)) ([],[])

> unzip [(1,2),(3,4),(5,6)]
> ([1,3,5],[2,4,6])


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