Saturday, February 2, 2013

HASKELL LISTS

HASKELL LISTS


REVISED: Saturday, February 3, 2024




Haskell Lists.

I.  HASKELL NUMERIC AND CHARACTER LISTS

The Data.List module is the home of all standard list functions.

Prelude>  :module +Data.List
Prelude>

Prelude>  "U" `isPrefixOf` "USA" -- isPrefixOf function matches at the beginning of a list.
True
it :: Bool
Prelude>

Prelude>  "S" `isInfixOf` "USA"   -- isInfixOf function matches anywhere in a list.
True
it :: Bool
Prelude>

Prelude>  "A" `isSuffixOf` "USA" -- isSuffixOf function matches at the end of a list.
True
it :: Bool
Prelude>

Prelude>  :type isPrefixOf
isPrefixOf :: Eq a => [a] -> [a] -> Bool
Prelude>

Prelude>  :type isInfixOf
isInfixOf :: Eq a => [a] -> [a] -> Bool
Prelude>

Prelude>  :type isSuffixOf
isSuffixOf :: Eq a => [a] -> [a] -> Bool
Prelude>    

A list can be of any length.

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

[]  pronounced "nil" is an empty list.

Prelude> :type []
[] :: [t]
Prelude>

Haskell uses pattern matching to tell the compiler how to process data.

The module shown below has two patterns for the compiler to choose from. The first pattern is myMod [] and the second pattern is myMod (x:xs). The compiler makes a choice between the two patterns based on the contents of the function myMod argument. If the argument is an empty list [] the compiler chooses the myMod [] pattern. If the argument is a singleton list [x] or a list of [xs] the compiler chooses the myMod (x:xs) pattern. By convention, list arguments usually have an s suffix on their name; e.g., [xs] for a list of xs, or  [[xss],[]] for a list of lists and so forth.

The function syntax is as follows:

<function name> <function arguments> = <return values>

error is a Prelude function that allows the programmer to code a message to be printed when an exception error occurs. In the module shown below the programmer is telling the compiler that when myMod has the empty list [] as an argument to print the exception error message "Empty list!". The programmer can choose any message to be printed as long as the message in enclosed in double " " marks.

Module:

module MyMod where  -- All module names; i.e., MyMod start with a capital letter.

myMod :: [t] -> [t]  -- Function signature.
myMod [] = error "Empty list!"  -- When argument is an empty list [], prints exception error message.
myMod (x:xs) = xs  -- Pattern which returns xs.

GHCi:

Prelude>  :load MyMod
[1 of 1] Compiling MyMod               ( MyMod.hs, interpreted )
Ok, modules loaded: MyMod.
Prelude>

Prelude>  myMod []
*** Exception: Empty list!
Prelude> 

Prelude>  myMod [1,2,3,4,5,6,7,8,9,10]
[2,3,4,5,6,7,8,9,10] -- Notice the compiler return xs which is the tail of the list.
Prelude>  

A singleton pattern is a design pattern that restricts the instantiation of a class to one object. 

[a] is a singleton list (a:[]).

Prelude>  :t (:[])  -- Rotate (:[]) 90 degrees to the right and you see the head of a robot.
(:[]) :: a -> [a]
Prelude>  

[l, 2]  is read, "list with elements of type integer."

Prelude> :type [1,2]
[1,2] :: Num t => [t]
Prelude>

=> reads, "implies". The way to read the above is to say, “t being an instance of Num implies a list [t] of t's.

[True,False]  is read, "a list with elements of type Boolean."

Prelude> :type [True,False]
[True,False] :: [Bool]
Prelude>

[(1, 2), (2, 3)]  is read, "a list of tuples of Integers".

Prelude> :type [(1,2),(2,3)]
[(1,2),(2,3)] :: (Num t1, Num t) => [(t, t1)]
Prelude>

[[1, 2], [2, 3, 4]]  is read, "a list of Integer-lists".

Prelude> :type [[1,2],[2,3,4]]
[[1,2],[2,3,4]] :: Num t => [[t]]
Prelude>

A. HASKELL LISTS FROM GIVEN ELEMENTS

The value to the left of the :,  pronounced "cons" for construct, is placed as the first element of the list. cons is another word for :. In lists, : is actually a constructor that takes a value and another list, and returns a list.

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

Prelude> 1 : 2 : 3 : []
[1,2,3]
it :: Num a => [a]
Prelude>

We can also use the Prelude foldr function to show an example of the identity function. 

Prelude>  let myId = foldr (:) []
Prelude>

Prelude>  :type myId
myId :: [a] -> [a]
Prelude>

Prelude>  myId [1,2,3]
[1,2,3]
it :: Num a => [a]
Prelude>  

These examples are really singly-linked lists, and not arrays. Haskell does not have array primitives.

Prelude> 4: 5 : 6 : []
[4,5,6]
it :: Num a => [a]
Prelude>

Prelude> "1" : "2" : "3" : []
["1","2","3"]
it :: [[Char]]
Prelude>

Prelude> "4": "5": "6": []
["4","5","6"]
it :: [[Char]]
Prelude>

B. COMBINING HASKELL LISTS

Prelude> [1,2,3] ++ [4,5,6]     -- ++ is pronounced, "append"; and concatenates two lists.
[1,2,3,4,5,6]
it :: Num a => [a]
Prelude>

Prelude> ["1","2","3"] ++ ["4","5","6"]
["1","2","3","4","5","6"]
it :: [[Char]]
Prelude>

Prelude>  :type (++)   -- :t is the same as :type.
(++) :: [a] -> [a] -> [a]
Prelude>

Prelude>  concat [ ["1","2","3"] , ["4","5","6"] ]
["1","2","3","4","5","6"]   -- Prelude concat function removes one level of nesting; i.e., the inner square brackets.
it :: [[Char]]
Prelude>  

Prelude>  :type concat
concat :: [[a]] -> [a]
Prelude>

module MyApp2List where

(++)              :: [a] -> [a] -> [a]
[]        ++ ys = ys
(x:xs) ++ ys = x : (xs ++ yx)

II. ACCESSING HASKELL SUBLISTS

Strings are lists of characters; therefore, you can use list functions on strings.

A. ACCESSING THE FIRST ELEMENT OF A LIST

To access the first element of a list, we use the Prelude head function.

Prelude> :type head
head :: [a] -> a
Prelude>

a is the type variable. We can read the signature as “takes a list, all of whose elements have some type a, and returns a value of the same type a”.

Prelude> let ls = ["1","2","3","4","5","6"]  -- ls is immutable, it never changes.
Prelude>

Prelude> head ls -- Returns a new list containing the first list element of ls.
"1"
it :: [Char]
Prelude>

head is what is known as a partial function. There are certain inputs, i.e., empty list [], for which head will crash. 

Prelude>  head []
*** Exception: Prelude.head: empty list  -- Calling an exception or an error does not qualify as returning a value!
Prelude>  

Functions which have certain inputs that will make them recurse infinitely are also called partial. Functions which are well-defined on all possible inputs are known as total functions. It is good Haskell practice to avoid partial functions. Other partial Prelude functions include tail, init, last, and (!!).

Shown below is the Prelude tail function, which returns all but the head of a list.

Prelude> let ls =  ["1","2","3","4","5","6"]
Prelude>

You have to add ls to local memory because when you do the :load MyTail all local memory is erased.

Prelude> tail ls  -- Removes the first list element from list ls.
["2","3","4","5","6"]  -- Haskell creates a new list; this is not the original ls list.
it :: [[Char]]
Prelude>

Writing your own version of Prelude functions helps you learn Haskell. For example, the following myTail is a version of Prelude Tail.

Module:

module MyTail where  -- Module names; e.g., MyTail must always start with capital letter.

myTail            :: [t] -> [t]  -- Function names; e.g., myTail must always start with lower case letter.
myTail        [] = error "Empty list!"
myTail (x:xs) = xs

GHCi:

Prelude> :load MyTail
[1 of 1] Compiling MyTail               ( MyTail.hs, interpreted )
Ok, modules loaded: MyTail.
Prelude>

Prelude> let ls =  ["1","2","3","4","5","6"]
Prelude>

You have to add ls to local memory because when you do the :load MyTail all local memory is erased.

Prelude>  myTail ls
["2","3","4","5","6"]  -- The list returned by myTail function body is a copy of ls.
Prelude>  

Prelude> ls
["1","2","3","4","5","6"] -- Original ls is immutable; therefore, does not change.
Prelude>

B. ACCESSING THE LAST ELEMENT OF A LIST

Prelude function last, returns the very last element of a list.

Prelude> :type last
last :: [a] -> a
Prelude>

Prelude> last ls
"6"
it :: [Char]
Prelude>

Prelude> ls
["1","2","3","4","5","6"]  -- ls is immutable; therefore,  ls does not change.
Prelude>

Module:

module MyLast where

myLast            :: [t] -> t
myLast        [] = error "Empty list!"
myLast      [x] = x
myLast (x:xs) = myLast xs

GHCi:

Prelude>  :load MyLast
[1 of 1] Compiling MyLast               ( MyLast.hs, interpreted )
Ok, modules loaded: MyLast.
Prelude>

Prelude>  let ls = ["1","2","3","4","5","6"]
Prelude>

Prelude>  myLast ls
"6"
Prelude>

C. ACCESSING AN ELEMENT AT A GIVEN INDEX

If you want to get an element out of a list by index, use !! pronounced index.

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

Prelude> ["1","2","3","4","5","6"] !! 3
"4"
it :: [Char]
Prelude>

There are both "zero based indexes" and "one based indexes". Zero based indexes start with zero. One based indexes start with one. Haskell uses zero based indexes for lists. Therefore, in our example above; index 0 would return 1, index 1 would return 2, index 2 would return 3, and index 3 would return 4.

D. ACCESSING THE FIRST N ELEMENTS

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

The -> is right associative; therefore, take gives type Int to a function.

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

The function take takes one argument, an Int, and returns another function ([a] -> [a]). That other function also takes one argument, a list [a] , and returns a list [a] of the same type as its result.

The take function has two arguments: an integer n, and a list ls; and produces the first n elements of ls. By convention a list is written ls and a list of lists would be written lss each list argument with a s suffix.

Prelude> take 4 ["1","2","3","4","5","6"]
["1","2","3","4"]
it :: [[Char]]
Prelude>

Prelude>  takeWhile (<= 5) [1..]
[1,2,3,4,5]
Prelude>  

Module:

module MyTake where

myTake                :: (Ord a, Num a) => a -> [t] -> [t]
myTake n _
      | n <= 0         = []                                    -- Checking for negative numbers.
myTake _ []         = []                                    -- Checking for empty list.
myTake n (x:xs)  = x:myTake (n-1) xs  -- Checking all other cases.

GHCi:

Prelude>  :load MyTake
[1 of 1] Compiling MyTake               ( MyTake.hs, interpreted )
Ok, modules loaded: MyTake.
Prelude>

Prelude>  myTake (-5) [1,2,3,4,5,6]
[]
Prelude>

Prelude>  myTake 5 []
[]
Prelude>

Prelude>  myTake 5 [1,2,3,4,5,6,7,8,9,10]
[1,2,3,4,5]
Prelude>  

E. ACCESSING THE LAST N ELEMENTS

Prelude> :type reverse
reverse :: [a] -> [a]
Prelude>

Prelude> reverse . take 4 . reverse $ ["1","2","3","4","5","6"]
["3","4","5","6"]
it :: [[Char]]
Prelude>

The dot . is the function composition operator, dot is read as, "after". The dot . operator has very high precedence, surpassed only by function application.

Function composition is the act of pipelining the result of one function, to the input of another, creating an entirely new function. This can be done with any two functions, where the argument type of the first is the return type of the second.

$ is pronounced, "apply". When a $ is encountered, the expression on its right is applied as the parameter to the function on its left.

F. ACCESSING THE N ELEMENTS STARTING FROM INDEX M

Prelude> :type drop
drop :: Int -> [a] -> [a]
Prelude>

Prelude> take 4 $ drop 1 ["1","2","3","4","5","6"]
["2","3","4","5"]
it :: [[Char]]
Prelude>

module Drop where
drop                       :: Int -> [a] -> [a]
drop 0         xs       = xs
drop (n+1) []        = []
drop (n+1) (_:xs) = drop n xs

G. SPLITTING A STRING INTO A LIST OF WORDS

Prelude> :type words
words :: String -> [String]
Prelude>

Prelude> words "Mary had a little lamb."
["Mary","had","a","little","lamb."]
it :: [String]
Prelude>

Prelude>  unwords ["Mary","had","a","little","lamb."]
"Mary had a little lamb."
it :: String
Prelude>  

H. SPLITTING A LIST INTO TWO PARTS

Prelude> :type splitAt
splitAt :: Int -> [a] -> ([a], [a])
Prelude>

Prelude> splitAt 12 "abcdefghijklmnopqrstuvwxyz"
("abcdefghijkl","mnopqrstuvwxyz")
Prelude>
Prelude> splitAt 12 ['a'..'z']
("abcdefghijkl","mnopqrstuvwxyz")
Prelude>

I. LENGTH OF A LIST

The length function tells us how many elements are in a list.

Prelude> :type length
length :: [a] -> Int
Prelude>

Prelude> length "abcdefghijklmnopqrstuvwxyz"
26
Prelude> length ['a'..'z']
26
Prelude>length [1..10]
10
Prelude>

module Length where

length            :: [a] -> Int
length        [] = 0
length (_:xs) = 1 + length xs
{-
length maps the empty list to 0, and any non-empty list to
the successor of the length of its tail.
-}

Prelude> :{
Prelude| len [] = 0

Prelude| len (_:xs) = 1 + len xs
Prelude| :}
Prelude> len [1,2,3,4,5,6,7,8,9,10]

10
Prelude>


Prelude> let myLength = sum . map (\_ -> 1)
Prelude> myLength [1,2,3,4]
4

J. REVERSE A LIST

Prelude> :type reverse
reverse :: [a] -> [a]
Prelude>

Prelude> reverse [1,2,3]
[3,2,1]
it :: Num a => [a]
Prelude>

module Reverse where

reverse            :: [a] -> [a]
reverse        [] = []
reverse (x:xs) = reverse xs ++ [x]
{-
reverse maps the empty list to the empty list
and any non-empty list to the reverse of its tail
appended to its head.
-}

The process of interpreting code by substituting equals-for-equals is known as equational reasoning. For example, with equational reasoning we can compute the reverse of 1, 2, 3 as follows:

reverse [1,2,3]
=
reverse [2,3] ++ [1]
=
(reverse [3] ++ [2]) ++ [1]
=
((reverse [] ++ [3]) ++ [2]) ++ [1]
=
(([] ++ [3]) ++ [2]) ++ [1]
=
[3,2,1]

K. APPLY A FUNCTION TO EACH ELEMENT IN A LIST

The higher-order library function called map applies a function; for example, (5*) to every element of a list.

Prelude> :type map
map :: (a -> b) -> [a] -> [b]
Prelude>

Prelude> map (5*) [1, 2, 3, 4, 5, 6]
[5, 10, 15, 20, 25, 30]
it :: Num b => [b]
Prelude>

Using (5*) is called sectioning notation which is the same as using an anonymous function fiveX = \x -> x * 5.

Prelude>  let fiveX = \x -> x * 5
Prelude>

Prelude>  fiveX 2
10
Prelude>

Prelude>  :type fiveX
fiveX :: Num a => a -> a
Prelude>  

The map function defined using list comprehension:

map f xs = [f x | x <- xs]

The map function defined using recursion:

map f []        = []
map f (x:xs) = f x : map f xs

L. FILTER A LIST

Prelude> :type filter
filter :: (a -> Bool) -> [a] -> [a]
Prelude>

filter cannot add elements; it can only remove them. When we filter we are choosing whether to keep an element of a list, depending on whether or not a particular predicate holds. A predicate is a function of type Int -> Bool which returns True for those elements which should be kept, and False for those which should be discarded.

filter returns a list constructed from members of a list, the second argument, fulfilling a condition given by the predicate, the first argument.

Prelude> filter (>5) [1, 2, 3, 4, 5, 6, 7, 8]
[6, 7, 8]
it :: (Ord a, Num a) => [a]
Prelude>

Filter defined using list comprehension:

filter p xs = [x | x <- xs, p x]

Filter defined using recursion:

filter p []        = []
filter p (x:xs)
    | p x            = x : filter p xs
    | otherwise = filter p xs

M. FOLD A LIST

Any function that traverse a list from left to right or right to left, one element by element, and accumulates a result, can be implemented with a fold.

Prelude> :type foldl
foldl :: (b -> a -> b) -> b -> [a] -> b
Prelude>

foldl takes a function which turns a b and a b into a b, an initial value of type b and a list of as. It produces a b.

Prelude> :type foldr
foldr :: (a -> b -> b) -> b -> [a] -> b
Prelude>

fold takes in a function and folds it in between the elements of a list. foldr folds from the right and foldl folds from the left.

sum       = foldr (+)   0

product = foldr (*)    1

or          = foldr (||)   False

and        = foldr (&&) True

Foldr defined using recursion and the above notation:

f = (+)

v = 0

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

The compiler is able to turn most recursions into loops. This is called tail recursion optimization, where the recursive call at the very end of a function is simply turned into a goto to the beginning of the function. 

Prelude> import Data.Foldable
Prelude>

Prelude> Data.Foldable.foldl (+) 0 [1..5]     -- Zero indexed, 0 starting point.
15
it :: (Num a, Enum a) => a
Prelude>

This is the same as:

0 + 1 + 2 + 3 + 4 + 5

which equals 15.

This is the same as:

sum2            :: Num a => [a] -> a
sum2 []        = 0
sum2 (x:xs) = x + sum2 xs

Prelude>  :load sum2
[1 of 1] Compiling Main             ( sum2.hs, interpreted )
Ok, modules loaded: Main.
Prelude>

Prelude>  sum2 [0,1,2,3,4,5]
15
Prelude>

sum2 [0,1,2,3,4,5]
=
foldr (+) 0 [0,1,2,3,4,5]
=
foldr (+) 0 (0:(1:(2:(3:(4:(5:[]))))))  -- fold right
=
0+(1+(2+(3+(4+(5+0)))))
=
6

N. ZIP A LIST

As shown below zip transposes a pair of lists ([a] , [b]) into a list of pairs [(a, b)] :

Prelude> :type zip
zip :: [a] -> [b] -> [(a, b)]
Prelude>

The library function zip produces a new list by pairing successive elements from two existing lists until either or both are exhausted.

Prelude> zip [1,2,3] [9,8,7]
[(1,9),(2,8),(3,7)]
it :: (Num b, Num a) => [(a, b)]
Prelude>

Module:

module MyZip where

myZip                       :: [a] -> [b] -> [(a,b)]     -- Function signature.
myZip  []  _              = []                                           -- [a] becomes empty first.
myZip  _   []             = []                                           -- [b] becomes empty first.
myZip (x:xs) (y:ys) = (x,y) : myZip xs ys             

GHCi:

Prelude>  :load MyZip
[1 of 1] Compiling MyZip               ( MyZip.hs, interpreted )
Ok, modules loaded: MyZip.
Prelude>

Prelude>  let ls1 = ["1", "2", "3"]
Prelude>

Prelude>  let ls2 = ["4", "5", "6"]
Prelude>

Prelude>  myZip ls1 ls2
[("1","4"),("2","5"),("3","6")]
Prelude>  

O. ZIPWITH A LIST

Prelude> :type zipWith
zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
Prelude>

zipWith makes a list whose elements are calculated from a function and the elements of input lists occurring at the same position in both lists.

Prelude> zipWith (+) [1,2,3] [3,2,1]
[4,4,4]
it :: Num c => [c]
Prelude>

P. liftM

Prelude>  import Control.Monad
Prelude>

liftM promotes a function to a monad.

Prelude> :type liftM
liftM :: Monad m => (a1 -> r) -> m a1 -> m r
Prelude>

Prelude> import Control.Monad
Prelude>

"Copy Paste" the following script into your text editor, and "File, Save As" MaryTxtFile.txt in your working directory.

Mary had a little lamb,
its fleas were white as snow.
And everywhere that Mary went,
its fleas were sure to go.

Prelude>  :cd C:\Users\Tinnel\Haskell2024\
Prelude>

Prelude> liftM lines (readFile "MaryTxtFile.txt")
["Mary had a little lamb,","its fleas were white as snow.","And everywhere that Mary went,","its fleas were sure to go."]
it :: [String]
Prelude>

Q. LIST COMPARISONS

Lists can be compared if the elements within the lists can be compared. When using <, <=, >, and >= to compare lists, they are compared in lexicographical order. First the heads are compared. If they are equal then the second elements are compared, etc.

R. LIST COMPREHENSIONS

Let S be a set,   be for every,  be is an element of, and p(x) be a predicate.

Mathematically we can write the following statement.

∀x∈S, p(x)


For every x such that x is an element of the set S and satisfies the predicate p(x).

We write the above in Haskell as follows:

[ x | x <- S,  p x ]

In Haskell <- is pronounced "drawn from" and p x is called a condition, or "predicate".

Below, the function x which satisfies the predicate x+5  is drawn from the set [1,2,3].

Prelude>  [ x+5 | x <- [1,2,3] ]
[6,7,8]
it :: Num t => [t]
Prelude>

Prelude>  [ x | x <- [2..10], 10 `mod` x  == 0]
[2,5,10]
Prelude>

Prelude>  [ team ++ " " ++ player | 
             team   <- ["red", "blue"], 
             player <- ["soldier", "pyro", "scout"] ]  -- Surprised? Try it.
["red soldier","red pyro","red scout","blue soldier","blue pyro","blue scout"]
it :: [[Char]]
Prelude> 

The following is accepted by Prelude as shown above because it is one single line of code:

[ team ++ " " ++ player | team   <- ["red", "blue"], player <- ["soldier", "pyro", "scout"] ] 

List comprehensions are used for building more specific lists out of general lists.

S is a set.
is an element of.
is a set of all natural numbers.

S = { x * 3 | x ∈ ℕ, (x * 3) ≦ 51 }

Prelude>  [x*3 | x <- [0..], x*3 <= 51]  
[0,3,6,9,12,15,18,21,24,27,30,33,36,39,42,45,48,51Interrupted.
Prelude>

In the example above GHCi will stop processing at 51. There is a tool bar at the top of the GHCi window. Select Actions in the GHCi tool bar, and then select Stop; or press Ctrl+C to interrupt processing and to return to the Prelude> prompt.

S = { x * 3 | x ∈ [12..20], (x * 3) ≦ 51 }

Prelude> [x*3 | x <- [12..20], x*3 <= 51]  
[36,39,42,45,48,51]
it :: (Ord t, Num t, Enum t) => [t]
Prelude>

The part before the pipe |, is the output function x*3. x is drawn from the input set of 12 to 20. For every element in 12..20 that we have bound to x we get that element x multiplied by 3 if it satisfies the condition, predicate, of being <= 51.

List comprehensions are an expressive shorthand for building computations on lists.

S. LIST DIFFERENCE \\ OPERATOR

Prelude> :type (\\)
(\\) :: Eq a => [a] -> [a] -> [a]
Prelude>

The list difference \\ operator takes two lists, goes through the second and for each item, removes the first instance of the same item from the first list.

Prelude> import Data.List
Prelude>

Prelude> [1..10] \\ [2, 3, 5, 8]
[1,4,6,7,9,10]
it :: (Num a, Eq a, Enum a) => [a]
Prelude>

[12,3,4,5,6,7,8,9,10]        -- First list [1..10].
[    2,3,    5,       8           ]       -- Second list.
[1,      4,   6,7,   9,10]

T. NUB

nubeliminates all duplicate elements from a list.

Prelude>  :type nub
nub :: Eq a => [a] -> [a]

Prelude>

Prelude>  import Data.List
Prelude>

Prelude>  nub [1,1,2,2,3,3,4,4,5,5]
[1,2,3,4,5]
Prelude>

U. INIT

init, returns a list of all but the last element of its input.

Prelude>  :type init
init :: [a] -> [a]
Prelude>

Prelude>  :info init
init :: [a] -> [a] -- Defined in `GHC.List'
Prelude>

Prelude>  init "hello"
"hell"
it :: [Char]
Prelude>  

Module:

module MyInit where

myInit            :: [t] -> [t]
myInit        [] = error "Empty list!"
myInit      [_] = []
myInit (x:xs) = x:myInit xs

GHCi:

Prelude>  :load MyInit
[1 of 1] Compiling MyInit              ( MyInit.hs, interpreted )
Ok, modules loaded: MyInit.

Prelude>  let ls = ["1","2","3","4","5","6"]
Prelude>

Prelude>  myInit ls
["1","2","3","4","5"]
Prelude>

Prelude>  myInit ["1"]
[]
Prelude>

Prelude>  myInit []
*** Exception: Empty list!
Prelude>

V. ELEM

elem is the list membership predicate, usually written in infix form, e.g., x `elem` xs.

Prelude>  :type elem
elem :: Eq a => a -> [a] -> Bool
Prelude>  

Prelude>  5 `elem`  [1,2,3,4,5]  -- Infix uses backticks ` not apostrophes '.
True
Prelude>

Module:

module MyElem where

myElem               :: Eq a => a -> [a] -> Bool
myElem _ []        = False
myElem e (x:xs)
        | e == x      = True
| otherwise = myElem e xs

GHCi:

Prelude>  :load MyElem
[1 of 1] Compiling MyElem               ( MyElem.hs, interpreted )
Ok, modules loaded: MyElem.
Prelude>

Prelude>  myElem 5 [1,2,3,4,5]
True
Prelude>

Prelude>  myElem 5 [1,2,3,4]
False
Prelude>

W. SORT

sort sorts a list.

Prelude>  :type sort

sort :: Ord a => [a] -> [a]

Prelude>

Prelude>  sort [4,3,6,9,1,2]

[1,2,3,4,6,9]
Prelude>

X. PRODUCT

Prelude> product [4,3,6,9,1,2]
1296
Prelude>

III. CONCLUSION

In this tutorial, you have received an introduction to Haskell lists.

IV. REFERENCES

Bird, R. (2015). Thinking Functionally with Haskell. Cambridge, England: Cambridge University Press.

Davie, A. (1992). Introduction to Functional Programming Systems Using Haskell. Cambridge, England: Cambridge University Press.

Goerzen, J. & O'Sullivan, B. &  Stewart, D. (2008). Real World Haskell. Sebastopol, CA: O'Reilly Media, Inc.

Hutton, G. (2007). Programming in Haskell. New York: Cambridge University Press.

Lipovača, M. (2011). Learn You a Haskell for Great Good!: A Beginner's Guide. San Francisco, CA: No Starch Press, Inc.

Thompson, S. (2011). The Craft of Functional Programming. Edinburgh Gate, Harlow, England: Pearson Education Limited.