Difference between revisions of "Cookbook/Lists and strings"

From HaskellWiki
Jump to: navigation, search
m (Fixed broken links)
 
(26 intermediate revisions by 6 users not shown)
Line 1: Line 1:
Since strings are lists of characters, you can use any available list function.
 
  +
== Lists ==
   
= Lists =
 
  +
In Haskell, lists are what Arrays are in most other languages.
   
In Haskell, lists are what Arrays are in most other languages. Haskell has all of the general list manipulation functions, see also <hask>Data.List</hask>.
 
  +
=== Creating simple lists ===
   
<haskell>
 
  +
{| class="wikitable"
head [1,2,3] --> 1
 
  +
|-
tail [1,2,3] --> [2,3]
 
  +
! Problem
length [1,2,3] --> 3
 
  +
! Solution
init [1,2,3] --> [1,2]
 
  +
! Examples
last [1,2,3] --> 3
 
  +
|-
  +
| creating a list with given elements
  +
| -
  +
|<haskell>
  +
3 : 12 : 42 : [] --> [3,12,42]
  +
'f' : 'o' : 'o' : [] --> "foo"
 
</haskell>
 
</haskell>
 
  +
|-
Furthermore, Haskell supports some neat concepts.
 
  +
| creating a list with stepsize 1
 
  +
| -
== Infinite lists ==
 
  +
|<haskell>
<haskell>
 
  +
[1..10] --> [1,2,3,4,5,6,7,8,9,10]
Prelude> [1..]
 
  +
['a'..'z'] --> "abcdefghijklmnopqrstuvwxyz"
 
</haskell>
 
</haskell>
 
  +
|-
The list of all squares:
 
  +
| creating a list with different stepsize
<haskell>
 
  +
| -
square x = x*x
 
  +
|<haskell>
squares = map square [1..]
 
  +
[1,3..10] --> [1,3,5,7,9]
  +
['a','c'..'z'] --> "acegikmoqsuwy"
 
</haskell>
 
</haskell>
 
  +
|-
But in the end, you probably don't want to use infinite lists, but make them finite. You can do this with <hask>take</hask>:
 
  +
| creating an infinite constant list
 
  +
| -
<haskell>
+
|<haskell>
Prelude> take 10 squares
+
[1,1..] --> [1,1,1,1,1,...
[1,4,9,16,25,36,49,64,81,100]
 
 
</haskell>
 
</haskell>
  +
|-
  +
| creating an infinite list with stepsize 1
  +
| -
  +
| <haskell>
  +
[1..] --> [1,2,3,4,5,...
  +
</haskell>
  +
|}
   
== List comprehensions ==
+
=== List comprehensions ===
   
 
The list of all squares can also be written in a more comprehensive way, using list comprehensions:
 
The list of all squares can also be written in a more comprehensive way, using list comprehensions:
Line 48: Line 61:
   
   
== Combining lists ==
+
=== Combining lists ===
   
 
{| class="wikitable"
 
{| class="wikitable"
Line 56: Line 69:
 
! Examples
 
! Examples
 
|-
 
|-
| combining two strings
+
| combining two lists
| [http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v%3A%2B%2B (++)]
+
| [http://haskell.org/ghc/docs/latest/html/libraries/base-4.12.0.0/Prelude.html#v%3A%2B%2B (++)]
 
|<haskell>
 
|<haskell>
 
"foo" ++ "bar" --> "foobar"
 
"foo" ++ "bar" --> "foobar"
  +
[42,43] ++ [60,61] --> [42,43,60,61]
 
</haskell>
 
</haskell>
 
|-
 
|-
| combining many strings
+
| combining many lists
| [http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:concat concat]
+
| [http://haskell.org/ghc/docs/latest/html/libraries/base-4.12.0.0/Prelude.html#v:concat concat]
 
| <haskell>
 
| <haskell>
 
concat ["foo", "bar", "baz"] --> "foobarbaz"
 
concat ["foo", "bar", "baz"] --> "foobarbaz"
Line 69: Line 83:
 
|}
 
|}
   
== Accessing sublists ==
+
=== Accessing sublists ===
   
 
{| class="wikitable"
 
{| class="wikitable"
Line 77: Line 91:
 
! Examples
 
! Examples
 
|-
 
|-
| accessing the first character
+
| accessing the first element
| [http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:head head]
+
| [http://haskell.org/ghc/docs/latest/html/libraries/base-4.12.0.0/Prelude.html#v:head head]
 
|<haskell>
 
|<haskell>
 
head "foo bar baz" --> 'f'
 
head "foo bar baz" --> 'f'
 
</haskell>
 
</haskell>
 
|-
 
|-
| accessing the last character
+
| accessing the last element
| [http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v%3Alast last]
+
| [http://haskell.org/ghc/docs/latest/html/libraries/base-4.12.0.0/Prelude.html#v%3Alast last]
 
|<haskell>
 
|<haskell>
 
last "foo bar baz" --> 'z'
 
last "foo bar baz" --> 'z'
 
</haskell>
 
</haskell>
 
|-
 
|-
| accessing the character at a given index
+
| accessing the element at a given index
| [http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v%3A!! (!!)]
+
| [http://haskell.org/ghc/docs/latest/html/libraries/base-4.12.0.0/Prelude.html#v%3A!! (!!)]
 
|<haskell>
 
|<haskell>
 
"foo bar baz" !! 4 --> 'b'
 
"foo bar baz" !! 4 --> 'b'
 
</haskell>
 
</haskell>
 
|-
 
|-
| accessing the first <code>n</code> characters
+
| accessing the first <code>n</code> elements
| [http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:take take]
+
| [http://haskell.org/ghc/docs/latest/html/libraries/base-4.12.0.0/Prelude.html#v:take take]
 
| <haskell>
 
| <haskell>
 
take 3 "foo bar baz" --> "foo"
 
take 3 "foo bar baz" --> "foo"
 
</haskell>
 
</haskell>
 
|-
 
|-
| accessing the last <code>n</code> characters
+
| accessing the last <code>n</code> elements
| [http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:reverse reverse ], [http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:take take]
+
| [http://haskell.org/ghc/docs/latest/html/libraries/base-4.12.0.0/Prelude.html#v:reverse reverse ], [http://haskell.org/ghc/docs/latest/html/libraries/base-4.12.0.0/Prelude.html#v:take take]
 
| <haskell>
 
| <haskell>
 
reverse . take 3 . reverse $ "foobar" --> "bar"
 
reverse . take 3 . reverse $ "foobar" --> "bar"
 
</haskell>
 
</haskell>
 
|-
 
|-
| accessing the <code>n</code> characters starting from index <code>m</code>
+
| accessing the <code>n</code> elements starting from index <code>m</code>
| [http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:drop drop], [http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:take take]
+
| [http://haskell.org/ghc/docs/latest/html/libraries/base-4.12.0.0/Prelude.html#v:drop drop], [http://haskell.org/ghc/docs/latest/html/libraries/base-4.12.0.0/Prelude.html#v:take take]
 
| <haskell>
 
| <haskell>
 
take 4 $ drop 2 "foo bar baz" --> "o ba"
 
take 4 $ drop 2 "foo bar baz" --> "o ba"
Line 114: Line 128:
 
|}
 
|}
   
== Splitting lists ==
+
=== Splitting lists ===
   
   
Line 124: Line 138:
 
|-
 
|-
 
| splitting a string into a list of words
 
| splitting a string into a list of words
| [http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:words words]
+
| [http://haskell.org/ghc/docs/latest/html/libraries/base-4.12.0.0/Prelude.html#v:words words]
 
| <haskell>words "foo bar\t baz\n" --> ["foo","bar","baz"]
 
| <haskell>words "foo bar\t baz\n" --> ["foo","bar","baz"]
 
</haskell>
 
</haskell>
 
|-
 
|-
| splitting a string into two parts
+
| splitting a list into two parts
| [http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v%3AsplitAt splitAt]
+
| [http://haskell.org/ghc/docs/latest/html/libraries/base-4.12.0.0/Prelude.html#v%3AsplitAt splitAt]
 
| <haskell>splitAt 3 "foo bar baz" --> ("foo"," bar baz")
 
| <haskell>splitAt 3 "foo bar baz" --> ("foo"," bar baz")
 
</haskell>
 
</haskell>
 
|}
 
|}
   
= Strings =
+
== Strings ==
   
== Multiline strings ==
 
  +
Since strings are lists of characters, you can use any available list function.
  +
  +
=== Multiline strings ===
 
<haskell>
 
<haskell>
 
"foo\
 
"foo\
Line 142: Line 158:
 
</haskell>
 
</haskell>
   
== Converting between characters and values ==
+
=== Converting between characters and values ===
   
 
{| class="wikitable"
 
{| class="wikitable"
Line 151: Line 167:
 
|-
 
|-
 
| converting a character to a numeric value
 
| converting a character to a numeric value
| [http://haskell.org/ghc/docs/latest/html/libraries/base/Data-Char.html#v:ord ord]
+
| [http://haskell.org/ghc/docs/latest/html/libraries/base-4.12.0.0/Data-Char.html#v:ord ord]
 
|<haskell>
 
|<haskell>
import Char
+
import Data.Char
 
ord 'A' --> 65
 
ord 'A' --> 65
 
</haskell>
 
</haskell>
 
|-
 
|-
 
| converting a numeric value to a character
 
| converting a numeric value to a character
| [http://haskell.org/ghc/docs/latest/html/libraries/base/Data-Char.html#v%3Achr chr]
+
| [http://haskell.org/ghc/docs/latest/html/libraries/base-4.12.0.0/Data-Char.html#v%3Achr chr]
 
| <haskell>
 
| <haskell>
import Char
+
import Data.Char
 
chr 99 --> 'c'
 
chr 99 --> 'c'
 
</haskell>
 
</haskell>
 
|}
 
|}
   
== Reversing a string by words or characters ==
+
=== Reversing a string by words or characters ===
   
 
{| class="wikitable"
 
{| class="wikitable"
Line 174: Line 190:
 
|-
 
|-
 
| reversing a string by characters
 
| reversing a string by characters
| [http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:reverse reverse]
+
| [http://haskell.org/ghc/docs/latest/html/libraries/base-4.12.0.0/Prelude.html#v:reverse reverse]
 
|<haskell>
 
|<haskell>
 
reverse "foo bar baz" --> "zab rab oof"
 
reverse "foo bar baz" --> "zab rab oof"
Line 180: Line 196:
 
|-
 
|-
 
| reversing a string by words
 
| reversing a string by words
| [http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v%3Awords words], [http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:reverse reverse], [http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v%3Aunwords unwords]
+
| [http://haskell.org/ghc/docs/latest/html/libraries/base-4.12.0.0/Prelude.html#v%3Awords words], [http://haskell.org/ghc/docs/latest/html/libraries/base-4.12.0.0/Prelude.html#v:reverse reverse], [http://haskell.org/ghc/docs/latest/html/libraries/base-4.12.0.0/Prelude.html#v%3Aunwords unwords]
 
| <haskell>
 
| <haskell>
 
unwords $ reverse $ words "foo bar baz" --> "baz bar foo"
 
unwords $ reverse $ words "foo bar baz" --> "baz bar foo"
Line 186: Line 202:
 
|-
 
|-
 
| reversing a string by characters by words
 
| reversing a string by characters by words
| [http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v%3Awords words], [http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:reverse reverse], [http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:map map], [http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v%3Aunwords unwords]
+
| [http://haskell.org/ghc/docs/latest/html/libraries/base-4.12.0.0/Prelude.html#v%3Awords words], [http://haskell.org/ghc/docs/latest/html/libraries/base-4.12.0.0/Prelude.html#v:reverse reverse], [http://haskell.org/ghc/docs/latest/html/libraries/base-4.12.0.0/Prelude.html#v:map map], [http://haskell.org/ghc/docs/latest/html/libraries/base-4.12.0.0/Prelude.html#v%3Aunwords unwords]
 
| <haskell>
 
| <haskell>
 
unwords $ map reverse $ words "foo bar baz" --> "oof rab zab"
 
unwords $ map reverse $ words "foo bar baz" --> "oof rab zab"
Line 192: Line 208:
 
|}
 
|}
   
== Converting case ==
+
=== Converting case ===
   
 
{| class="wikitable"
 
{| class="wikitable"
Line 201: Line 217:
 
|-
 
|-
 
| converting a character to upper-case
 
| converting a character to upper-case
| [http://haskell.org/ghc/docs/latest/html/libraries/base/Data-Char.html#v%3AtoUpper toUpper]
+
| [http://haskell.org/ghc/docs/latest/html/libraries/base-4.12.0.0/Data-Char.html#v%3AtoUpper toUpper]
 
|<haskell>
 
|<haskell>
import Char
+
import Data.Char
toUpper 'a' --> "A"
+
toUpper 'a' --> 'A'
 
</haskell>
 
</haskell>
 
|-
 
|-
 
| converting a character to lower-case
 
| converting a character to lower-case
| [http://haskell.org/ghc/docs/latest/html/libraries/base/Data-Char.html#v%3AtoLower toLower]
+
| [http://haskell.org/ghc/docs/latest/html/libraries/base-4.12.0.0/Data-Char.html#v%3AtoLower toLower]
 
| <haskell>
 
| <haskell>
import Char
+
import Data.Char
toLower 'A' --> "a"
+
toLower 'A' --> 'a'
 
</haskell>
 
</haskell>
 
|-
 
|-
 
| converting a string to upper-case
 
| converting a string to upper-case
| [http://haskell.org/ghc/docs/latest/html/libraries/base/Data-Char.html#v%3AtoUpper toUpper], [http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:map map]
+
| [http://haskell.org/ghc/docs/latest/html/libraries/base-4.12.0.0/Data-Char.html#v%3AtoUpper toUpper], [http://haskell.org/ghc/docs/latest/html/libraries/base-4.12.0.0/Prelude.html#v:map map]
 
|<haskell>
 
|<haskell>
import Char
+
import Data.Char
 
map toUpper "Foo Bar" --> "FOO BAR"
 
map toUpper "Foo Bar" --> "FOO BAR"
 
</haskell>
 
</haskell>
 
|-
 
|-
 
| converting a string to lower-case
 
| converting a string to lower-case
| [http://haskell.org/ghc/docs/latest/html/libraries/base/Data-Char.html#v%3AtoLower toLower], [http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:map map]
+
| [http://haskell.org/ghc/docs/latest/html/libraries/base-4.12.0.0/Data-Char.html#v%3AtoLower toLower], [http://haskell.org/ghc/docs/latest/html/libraries/base-4.12.0.0/Prelude.html#v:map map]
 
| <haskell>
 
| <haskell>
import Char
+
import Data.Char
 
map toLower "Foo Bar" --> "foo bar"
 
map toLower "Foo Bar" --> "foo bar"
 
</haskell>
 
</haskell>
 
|}
 
|}
   
== Interpolation ==
+
=== Interpolation ===
   
 
TODO
 
TODO
   
== Performance ==
+
=== Performance ===
   
For high performance requirements (where you would typically consider
 
  +
Text handles character strings with better performance than Strings; it should be the prefered data type for UTF-8 encoded strings.
C), consider using [http://hackage.haskell.org/packages/archive/bytestring/latest/doc/html/Data-ByteString.html Data.ByteString].
 
   
== Unicode ==
 
  +
If observe that Text does not give sufficient performance, consider [http://hackage.haskell.org/packages/archive/bytestring/latest/doc/html/Data-ByteString.html Data.ByteString], which is essentially a byte array. It can contain UTF-8 characters, but handle with care! .
   
TODO
 
  +
=== Unicode ===
  +
  +
Current GHC (later than 6) encodes Strings and Text in UTF-8. This may change the behavior of some of the functions explained above when applied to characters beyond the traditional ASCII characters. Remember that not every character in UTF-8 encoding is one byte!

Latest revision as of 21:02, 6 January 2019

Lists

In Haskell, lists are what Arrays are in most other languages.

Creating simple lists

Problem Solution Examples
creating a list with given elements -
3 : 12 : 42 : []        --> [3,12,42]
'f' : 'o' : 'o' : []    --> "foo"
creating a list with stepsize 1 -
[1..10]                 --> [1,2,3,4,5,6,7,8,9,10]
['a'..'z']              --> "abcdefghijklmnopqrstuvwxyz"
creating a list with different stepsize -
[1,3..10]               --> [1,3,5,7,9]
['a','c'..'z']          --> "acegikmoqsuwy"
creating an infinite constant list -
[1,1..]                   --> [1,1,1,1,1,...
creating an infinite list with stepsize 1 -
[1..]                 --> [1,2,3,4,5,...

List comprehensions

The list of all squares can also be written in a more comprehensive way, using list comprehensions:

squares = [x*x | x <- [1..]]

List comprehensions allow for constraints as well:

-- multiples of 3 or 5
mults = [ x | x <- [1..], mod x 3 == 0 || mod x 5 == 0 ]


Combining lists

Problem Solution Examples
combining two lists (++)
"foo" ++ "bar"                  --> "foobar"
[42,43] ++ [60,61]              --> [42,43,60,61]
combining many lists concat
concat ["foo", "bar", "baz"]    --> "foobarbaz"

Accessing sublists

Problem Solution Examples
accessing the first element head
head "foo bar baz"      --> 'f'
accessing the last element last
last "foo bar baz"      --> 'z'
accessing the element at a given index (!!)
"foo bar baz" !! 4      --> 'b'
accessing the first n elements take
take 3 "foo bar baz"    --> "foo"
accessing the last n elements reverse , take
reverse . take 3 . reverse $ "foobar"    --> "bar"
accessing the n elements starting from index m drop, take
take 4 $ drop 2 "foo bar baz"            --> "o ba"

Splitting lists

Problem Solution Examples
splitting a string into a list of words words
words "foo bar\t baz\n"    --> ["foo","bar","baz"]
splitting a list into two parts splitAt
splitAt 3 "foo bar baz"    --> ("foo"," bar baz")

Strings

Since strings are lists of characters, you can use any available list function.

Multiline strings

"foo\
\bar"               --> "foobar"

Converting between characters and values

Problem Solution Examples
converting a character to a numeric value ord
import Data.Char
ord 'A'    --> 65
converting a numeric value to a character chr
import Data.Char
chr 99     --> 'c'

Reversing a string by words or characters

Problem Solution Examples
reversing a string by characters reverse
reverse "foo bar baz"                        --> "zab rab oof"
reversing a string by words words, reverse, unwords
unwords $ reverse $ words "foo bar baz"      --> "baz bar foo"
reversing a string by characters by words words, reverse, map, unwords
unwords $ map reverse $ words "foo bar baz"  --> "oof rab zab"

Converting case

Problem Solution Examples
converting a character to upper-case toUpper
import Data.Char
toUpper 'a'            --> 'A'
converting a character to lower-case toLower
import Data.Char
toLower 'A'            --> 'a'
converting a string to upper-case toUpper, map
import Data.Char
map toUpper "Foo Bar"  --> "FOO BAR"
converting a string to lower-case toLower, map
import Data.Char
map toLower "Foo Bar"  --> "foo bar"

Interpolation

TODO

Performance

Text handles character strings with better performance than Strings; it should be the prefered data type for UTF-8 encoded strings.

If observe that Text does not give sufficient performance, consider Data.ByteString, which is essentially a byte array. It can contain UTF-8 characters, but handle with care! .

Unicode

Current GHC (later than 6) encodes Strings and Text in UTF-8. This may change the behavior of some of the functions explained above when applied to characters beyond the traditional ASCII characters. Remember that not every character in UTF-8 encoding is one byte!