handouts/pep-ho.tex
changeset 273 b19227660752
parent 272 da3d30ae67ec
child 274 8980686aa2e8
equal deleted inserted replaced
272:da3d30ae67ec 273:b19227660752
   741 
   741 
   742 \noindent
   742 \noindent
   743 On top is the ``input'' list we want to transform; on the left is the
   743 On top is the ``input'' list we want to transform; on the left is the
   744 ``map'' function for how to transform each element in the input list
   744 ``map'' function for how to transform each element in the input list
   745 (the square function in this case); at the bottom is the result list of
   745 (the square function in this case); at the bottom is the result list of
   746 the map. This means that a map produces a \emph{new} list as a result,
   746 the map. This means that a map produces a \emph{new} list, unlike a
   747 unlike a for-loop in Java or C/C++ which would most likely update the list
   747 for-loop in Java or C/C++ which would most likely just update the
   748 exists in memory after the map.
   748 existing list.
   749 
   749 
   750 Now there are two ways to express such maps in Scala. The first way is
   750 Now there are two ways to express such maps in Scala. The first way is
   751 called a \emph{for-comprehension}. The keywords are \code{for} and
   751 called a \emph{for-comprehension}. The keywords are \code{for} and
   752 \code{yield}. Squaring the numbers from 1 to 8 with a for-comprehension
   752 \code{yield}. Squaring the numbers from 1 to 8 with a for-comprehension
   753 would look as follows:
   753 would look as follows:
   762 arbitrary, not just \code{n}) and compute the result of \code{n * n}.
   762 arbitrary, not just \code{n}) and compute the result of \code{n * n}.
   763 This way of writing a map resembles a bit the for-loops from imperative
   763 This way of writing a map resembles a bit the for-loops from imperative
   764 languages, even though the idea behind for-loops and for-comprehensions
   764 languages, even though the idea behind for-loops and for-comprehensions
   765 is quite different. Also, this is a simple example---what comes after
   765 is quite different. Also, this is a simple example---what comes after
   766 \code{yield} can be a complex expression enclosed in \texttt{\{...\}}.
   766 \code{yield} can be a complex expression enclosed in \texttt{\{...\}}.
   767 An example might be
   767 A more complicated example might be
   768 
   768 
   769 \begin{lstlisting}[numbers=none]
   769 \begin{lstlisting}[numbers=none]
   770 scala> for (n <- (1 to 8).toList) yield {
   770 scala> for (n <- (1 to 8).toList) yield {
   771          val i = n + 1
   771          val i = n + 1
   772          val j = n - 1
   772          val j = n - 1
   773          i * j
   773          i * j + 1
   774        }
   774        }
   775 res3: List[Int] = List(0, 3, 8, 15, 24, 35, 48, 63)
   775 res3: List[Int] = List(1, 4, 9, 16, 25, 36, 49, 64)
   776 \end{lstlisting}
   776 \end{lstlisting}
   777 
   777 
   778 As you can see in for-comprehensions above, we specified the list where
   778 As you can see in for-comprehensions above, we specified the list where
   779 each \code{n} comes from, namely \code{(1 to 8).toList}, and how each
   779 each \code{n} comes from, namely \code{(1 to 8).toList}, and how each
   780 element needs to be transformed. This can also be expressed in a second
   780 element needs to be transformed. This can also be expressed in a second
   786 \end{lstlisting}
   786 \end{lstlisting}
   787 
   787 
   788 \noindent In this way, the expression \code{n => n * n} stands for the
   788 \noindent In this way, the expression \code{n => n * n} stands for the
   789 function that calculates the square (this is how the \code{n}s are
   789 function that calculates the square (this is how the \code{n}s are
   790 transformed by the map).  It might not be obvious, but
   790 transformed by the map).  It might not be obvious, but
   791 for-comprehensions above are just syntactic sugar: when compiling, Scala
   791 for-comprehensions above are just syntactic sugar: when compiling such
   792 translates for-comprehensions into equivalent maps. This even works when
   792 code, Scala translates for-comprehensions into equivalent maps. This
   793 for-comprehensions get more complicated (see below).
   793 even works when for-comprehensions get more complicated (see below).
   794 
   794 
   795 The very charming feature of Scala is that such maps or
   795 The very charming feature of Scala is that such maps or
   796 for-comprehensions can be written for any kind of data collection, such
   796 for-comprehensions can be written for any kind of data collection, such
   797 as lists, sets, vectors, options and so on. For example if we instead
   797 as lists, sets, vectors, options and so on. For example if we instead
   798 compute the remainders modulo 3 of this list, we can write
   798 compute the remainders modulo 3 of this list, we can write
   850 \noindent The \code{if}-condition in this for-comprehension filters out
   850 \noindent The \code{if}-condition in this for-comprehension filters out
   851 all pairs where the sum is not even (therefore \code{(1, 2)} is not in
   851 all pairs where the sum is not even (therefore \code{(1, 2)} is not in
   852 the result because the sum is odd). 
   852 the result because the sum is odd). 
   853 
   853 
   854 To sum up, maps (or for-comprehensions) transform one collection into
   854 To sum up, maps (or for-comprehensions) transform one collection into
   855 another. For example a list of \code{Int}s into a list of squares, or a
   855 another. For example a list of \code{Int}s into a list of squares, and
   856 list of \code{Int}s into a set of \code{Int}s and so on. There is no need
   856 so on. There is no need for for-loops in Scala. But please do not be
   857 for for-loops in Scala. But please do not be tempted to write anything like
   857 tempted to write anything like
   858 
   858 
   859 \begin{lstlisting}[numbers=none]
   859 \begin{lstlisting}[numbers=none]
   860 scala> val cs = ('a' to 'h').toList
   860 scala> val cs = ('a' to 'h').toList
   861 scala> for (n <- (0 until cs.length).toList) 
   861 scala> for (n <- (0 until cs.length).toList) 
   862           yield cs(n).capitalize
   862           yield cs(n).capitalize
   874 \end{lstlisting}
   874 \end{lstlisting}
   875 
   875 
   876 \subsection*{Results and Side-Effects}
   876 \subsection*{Results and Side-Effects}
   877 
   877 
   878 While hopefully this all about maps looks reasonable, there is one
   878 While hopefully this all about maps looks reasonable, there is one
   879 complication: In the examples above we always wanted to
   879 complication: In the examples above we always wanted to transform one
   880 transform one list into another list (e.g.~list of squares),
   880 list into another list (e.g.~list of squares), or one set into another
   881 or one set into another set (set of numbers into set of
   881 set (set of numbers into set of remainders modulo 3). What happens if we
   882 remainders modulo 3). What happens if we just want to print out
   882 just want to print out a list of integers? In these cases the
   883 a list of integers? Then actually the for-comprehension
   883 for-comprehensions need to be modified. The reason is that \code{print},
   884 needs to be modified. The reason is that \code{print}, you
   884 you guessed it, does not produce any result, but only produces what is
   885 guessed it, does not produce any result, but only produces
   885 in the functional-programming-lingo called a \emph{side-effect}\ldots it
   886 what is in the functional-programming-lingo called a
   886 prints something out on the screen. Printing out the list of numbers
   887 \emph{side-effect}. Printing out the list of numbers from 1 to 5
   887 from 1 to 5 would look as follows
   888 would look as follows
       
   889 
   888 
   890 \begin{lstlisting}[numbers=none]
   889 \begin{lstlisting}[numbers=none]
   891 scala> for (n <- (1 to 5).toList) print(n)
   890 scala> for (n <- (1 to 5).toList) print(n)
   892 12345
   891 12345
   893 \end{lstlisting}
   892 \end{lstlisting}
   931 \begin{lstlisting}[numbers=none]
   930 \begin{lstlisting}[numbers=none]
   932 scala> (1 to 5).toList.foreach(print)
   931 scala> (1 to 5).toList.foreach(print)
   933 12345
   932 12345
   934 \end{lstlisting}
   933 \end{lstlisting}
   935 
   934 
   936 \noindent Again I hope this reminds you a bit of your
   935 \noindent 
   937 lambda-calculus lessons, where an explanation is given why
       
   938 both forms produce the same result.
       
   939 
       
   940 
       
   941 If you want to find out more about maps and functions with
   936 If you want to find out more about maps and functions with
   942 side-effects, you can ponder about the response Scala gives if
   937 side-effects, you can ponder about the response Scala gives if
   943 you replace \code{foreach} by \code{map} in the expression
   938 you replace \code{foreach} by \code{map} in the expression
   944 above. Scala will still allow \code{map} with side-effect
   939 above. Scala will still allow \code{map} with side-effect
   945 functions, but then reacts with a slightly interesting result.
   940 functions, but then reacts with a slightly interesting result.
       
   941 
       
   942 \subsection*{Aggregates}
       
   943 
       
   944 There is one more usage of for-loops in Java, C/C++ and the like:
       
   945 sometimes you want to \emph{aggregate} something about a list, for
       
   946 example to sum up all its elements. In this case you cannot use map,
       
   947 because maps \emph{transform} one data collection into another data
       
   948 collection. They cannot be used to generate a single integer
       
   949 representing an aggregate. So how is this done in Scala? Let us
       
   950 suppose you want to sum up all elements from a list. You might
       
   951 be tempted to write something like
       
   952 
       
   953 \begin{lstlisting}[numbers=none]
       
   954 var cnt = 0
       
   955 for (n <- (1 to 8).toList) {
       
   956   cnt += n
       
   957 }
       
   958 print(cnt)
       
   959 \end{lstlisting}
       
   960 
       
   961 \noindent
       
   962 and indeed is accepted Scala code and produces the expected result,
       
   963 namely \code{36}, \textbf{BUT} this is imperative style and not
       
   964 permitted. It uses a \code{var} and therefore violates the immutability
       
   965 property I ask for in your code.
       
   966 
       
   967 So how to do that same thing without using a \code{var}? Well there are
       
   968 several ways. One way is to define the following recursive
       
   969 \code{sum}-function:
       
   970 
       
   971 \begin{lstlisting}[numbers=none]
       
   972 def sum(xs: List[Int]) : Int = 
       
   973   if (xs.isEmpty) 0 else xs.head + sum(xs.tail)
       
   974 \end{lstlisting}  
       
   975 
       
   976 \noindent
       
   977 You can then call \code{sum((1 to 8).toList)} and obtain the same result
       
   978 without a mutable for-loop. Obviously for simple things like sum, you
       
   979 could have written \code{xs.sum} in the first place. But not all
       
   980 aggregate functions are pre-defined and often you have to write your own
       
   981 recursive function for this.
       
   982 
   946 
   983 
   947 \subsection*{Higher-Order Functions}
   984 \subsection*{Higher-Order Functions}
   948 
   985 
   949 \subsection*{Types}
   986 \subsection*{Types}
   950 
   987