Skip to content

Instantly share code, notes, and snippets.

@vpayno
Last active December 23, 2020 03:56
Show Gist options
  • Save vpayno/8ba8c5e933ec9719a616 to your computer and use it in GitHub Desktop.
Save vpayno/8ba8c5e933ec9719a616 to your computer and use it in GitHub Desktop.
Haskell Cheat Sheets - Lists

By Victor Payno

Lists

Rules

  • Lists are composed of homogenous data.

  • Strings are character lists.

  • You can compare lists of different sizes.

List Manipulation

  • Use ++ to append a list to another list. Haskell has to walk the whole list to find the end of the list so it can append the other list.
newList = [1,2,3] ++ [4,5,6]
  • Use the cons operator, :, to prepend a single item to a list.
newList = 5:[1,2,3,4]
  • Use the !! operator to access an element from a list. The indicies start at 0.
2 == [1,2,3,4] !! 1
  • You can use <, >, <=, >=, ==, and /= to compare lists. Lists are compared element by element starting at the heads.

  • You can use head, tail, last, and init to get the first, all but the first, the last, and all but the last elements in the list respectively.

  • You can use length to get the count of elements in a list.

3 = length [1,2,3]
  • You can use null to test if a list is empty.
True == null []
False == null [1,2,3]
  • You can use reverse to reverse the order of the elements in a list.
[3,2,1] == reverse [1,2,3]
  • You can use take to extract X number of elements starting from the beginning of a list.
[1,2] == take 2 [1,2,3,4]
  • Use drop to remove X elements from the beginning of a list.
[3,4] == drop 2 [1,2,3,4]
  • minimum and maximum return the smallest and largest element in the list.

  • sum returns the sum of the elements in the list.

  • product returns the product of the elements in the list.

  • Use elem as an infix function to test if an item is in the list.

True == 4 `elem` [1,2,3,4]
False == elem 7 [1,2,3,4]

Ranges

  • Use the .. notation to create a range. Ranges include the start and endpoints.
20 == length [1..20]
  • Specify a step for the range by listing the first two elements and then the .. operator and the end element.
10 == length [2,4..20]
  • You can reverse the order of a range by reversing the numbers in the range call.
[3,2,1] == [3..1]
  • Create an infinite range by not specifying and endpoint for the range. This isn't lazy, it will try to do it.
[1..]
  • Specify a lazy infinite list by only asking for a subset.
12 == length (take 12 [1,3..])
  • cycle will take a list and make it infinite.
[1,2,3,1,2,3] == take 6 (cycle [1,2,3])
['SOS SOS SOS '] == take 3 (cycle 'SOS ')
  • repeat takes an element and uses it to create an infinite list with just that element.
[3,3,3] == take 3 (repeat 3)
  • The replicate function is easier to use.
[1,1,1] == replicate 3, 1
  • To reverse a range, you need to specify the step!
[5..0]
> []

[5,4..0]
> [5,4,3,2,1,0]

List Comprehension

  • Used to generate a specific set out of a generic set.

  • Basic comprehension that generates a set of 10 numbers and doubles the numbers.

[x*2 | x <- [1..10]]
  • Comprehension with a conditional. This example only returns the numbers in the same set that are equal or larger than 12. Weeding out lists by predicates is also called filtering.
[x*2 | x <- [1..10], x*2 >= 12]
  • You can also use list comprehension to generate a list with elements of a different type.
pingPong input = [if n < 10 then "ping" else "pong" | n <- input, even n]
pingPong [6..12]
  • Multiple predicates are also allowed.
[x | x <- [1..20], 0 == x `mod` 3, 0 == x `mod` 5, x /= 11]
  • Generating a list of Prime numbers is super easy.
isPrime n = if 0 == length [i | i <- [2..(n-1)], 0 == n `mod` i] then True else False

getPrimes n = [i | i <- [1..n], isPrime i]

getPrimes 23
> [1,2,3,5,7,11,13,17,19,23]
  • Generating the first n Prime numbers using an infinite list is just as easy.
isPrime n = null [i | i <- [2..(n-1)], 0 == n `mod` i]

getPrimes n = take n [i | i <- [1..], isPrime i]

getPrimes 20
> [4,6,8,9,10,12,14,15,16,18,20,21,22,24,25,26,27,28,30,32]
  • Generating the first n Prime numbers starting at m while still using an infinite list.
getPrimes' n m = take n [i | i <- [m..], isPrime i]

getPrimes' 10 100000
> [100003,100019,100043,100049,100057,100069,100103,100109,100129,100151]
  • You can use list comprehension to count items in a list. Use an underscore when you want to throw away the item drawn from the list.
length' list = sum [1 | _ <- list]

length' [1..20]
> 20
  • You can use multiple lists with list comprehension.
Prelude> [x+y | x <- [5,4..0], y <- [0..5]]
[5,6,7,8,9,10,4,5,6,7,8,9,3,4,5,6,7,8,2,3,4,5,6,7,1,2,3,4,5,6,0,1,2,3,4,5]

  • Let's get the index number of an element in an array.
let getIndex list element = [index | (index, item) <- zip [0..] list, item == element]

getIndex ['a'..'z'] 'r'
> [17]

getIndex ['a'..'z'] 'r' !! 0
> 17
  • Now let's write functions to change the case of a character.
upperChar letter = if letter `elem` ['a'..'z'] 
    then ['A'..'Z'] !! (getIndex ['a'..'z'] letter !! 0) 
    else letter

upperChar 'a'
> 'A'

upperChar 'A'
> 'A'

upperChar '.'
> '.'
lowerChar letter = if letter `elem` ['A'..'Z'] 
    then ['a'..'z'] !! (getIndex ['A'..'Z'] letter !! 0) 
    else letter

lowerChar 'A'
> 'a'

lowerChar 'a'
> 'a'

lowerChar '.'
> '.'
flipCharCase letter = if letter `elem` ['a'..'z'] 
    then upperChar letter 
    else if letter `elem` ['A'..'Z'] 
         then lowerChar letter 
         else letter

flipCharCase 'a'
> 'A'

flipCharCase 'B'
> 'b'

flipCharCase ':'
> ':'

  • We can also have fun with strings. Let's manipulate the case of a whole string.
lowercase string = [lowerChar letter | letter <- string]

lowercase "Hello World!"
> "hello world!"
uppercase string = [upperChar letter | letter <- string]

uppercase "Hello World!"
> "HELLO WORLD!"
flipcase string = [flipCharCase letter | letter <- string]

flipcase "Hello World!"
> "hELLO wORLD!"

(Ignore this part. It took forever to get the characters to work so I didn't want to delete it.)

['a'..'z'] ++ ['A'..'Z'] ++ [' ', ',', '.', ';', ':', '-', '_', '!', '@', '#', '$', '%', '^', '&', '*', '\'', '(', ')', '{', '}', '\\', '~', '[', ']', '/']
> "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ ,.;:-_!@#$%^&*'(){}\\~[]/"
  • We can also use list comprehension on nested lists (multi-dimensional arrays in other languages).
nestedLists = [[0,1,2,3,4,5], [10,11,12,13,14,15], [20,21,22,23,24,25]]

let evenOnly outer = [[n | n <- inner, even n] | inner <- outer]

evenOnly nestedLists
> [[0,2,4],[10,12,14],[20,22,24]]

oddOnly outer = [[n | n <- inner, odd n] | inner <- outer]

oddOnly nestedLists
> [[1,3,5],[11,13,15],[21,23,25]]

primeOnly outer = [[n | n <- inner, isPrime n] | inner <- outer]

primeOnly nestedLists
> [[0,1,2,3,5],[11,13],[23]]

Tuples

Rules
  • They don't have to be homogeneous like a list!

  • Can only store a discrete number of elements.

  • The number of elements and their types define the type of the tuple.

  • No such thing as a singleton tuple but there are singleton lists (eg. [1]). So (-1) is not a tuple!

  • You can only compare tuples of the same size and types.

Extracting Data From Two Element Tuples

The fst function returns the first element of a tuple pair.

fst (1,2)
> 1)

The snd function returns the second element of a tuple pair.

snd (1,2)
> 2
Using the zip Function

The zip function takes two lists and uses them to create 2-item tuples.

For example:

zip [0,2..10] [1,3..10]
> [(0,1),(2,3),(4,5),(6,7),(8,9)]

Since tuples can be made up of different type elements we can mix them using zip.

zip [1..6] ['a'..'f']
[(1,'a'),(2,'b'),(3,'c'),(4,'d'),(5,'e'),(6,'f')]

zip is also smart enough that it will do the right thing with two lists that aren't the same size (it will stop when it reaches the end of the smaller list).

zip [1..26] ['a'..'f']
> [(1,'a'),(2,'b'),(3,'c'),(4,'d'),(5,'e'),(6,'f')]

zip [1..6] ['a'..'z']
> [(1,'a'),(2,'b'),(3,'c'),(4,'d'),(5,'e'),(6,'f')]

zip is also lazy.

zip [1..6] ['a'..]
> [(1,'a'),(2,'b'),(3,'c'),(4,'d'),(5,'e'),(6,'f')]

zip [1..] ['a'..'f']
> [(1,'a'),(2,'b'),(3,'c'),(4,'d'),(5,'e'),(6,'f')]

take 3 (zip [1..] ['a'..])
> [(1,'a'),(2,'b'),(3,'c')]

Math Problems

  • Generate a list of triangles with lengths equal to or less than 10.
[(a,b,c) | c <- [1..10], b <- [1..10], a <- [1..10]]
  • Generate a list of equilateral triangles.
[(a,b,c) | c <- [1..10], b <- [1..10], a <- [1..10], a == b, a == c]
  • Generate a list of isosceles triangles.
[(a,b,c) | c <- [1..10], b <- [1..10], a <- [1..10], a == b, a /= c]
  • Generate a list of right triangles.
[(a,b,c) | c <- [1..10], b <- [1..10], a <- [1..10], a^2 + b^2 == c^2]
  • Generate a list of right triangles who's b side is never larger than c and a side is never larger than b.
[(a,b,c) | c <- [1..10], b <- [1..c], a <- [1..b], a^2 + b^2 == c^2]
  • Since strings are lists we can use them where lists are expected.
length "Hello World!"
> 12

head "Hello World!"
> 'H'

take 6 "Hello World!"
> "Hello "
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment