| 754 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |      1 | \documentclass{article}
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |      2 | \usepackage{../style}
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |      3 | \usepackage{../langs}
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |      4 | \usepackage{marvosym}
 | 
| 917 |      5 | \usepackage{tcolorbox}
 | 
|  |      6 | %% \usepackage[]{hvextern}
 | 
| 754 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |      7 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |      8 | %cheat sheet
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |      9 | %http://worldline.github.io/scala-cheatsheet/
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     10 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     11 | \begin{document}
 | 
| 994 |     12 | \fnote{\copyright{} Christian Urban, King's College London, 2020, 2021, 2023, 2025}
 | 
| 754 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     13 | 
 | 
| 917 |     14 | \section*{Scala 3 in 6CCS3CFL}
 | 
| 754 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     15 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     16 | For the coursework in this module you are free to use any programming
 | 
| 756 |     17 | language you like, but I will show you all my code using Scala---I
 | 
| 917 |     18 | hope you have fond memories of Scala from PEP. The only difference
 | 
| 965 |     19 | with PEP is that I will the Ammonite REPL for Scala 3.
 | 
| 830 |     20 | 
 | 
| 917 |     21 | \begin{tcolorbox}[colback=red!5!white,colframe=red!75!black]
 | 
|  |     22 | If you intend to submit your code for the CW in Scala, you \underline{MUST} submit code that
 | 
|  |     23 | is compatible with Scala 3!! This is to make it easier for me to test
 | 
|  |     24 | your code and the changes between Scala 2 from last year PEP to Scala
 | 
|  |     25 | 3 in CFL are not that great. In fact, most changes are just some new
 | 
|  |     26 | syntax.
 | 
|  |     27 | \end{tcolorbox}\medskip
 | 
|  |     28 | 
 | 
|  |     29 | \noindent
 | 
|  |     30 | If you need a reminder of the Scala handouts from PEP updated to Scala 3
 | 
|  |     31 | have a look here
 | 
| 994 |     32 | \hr{https://cflmark.nms.kcl.ac.uk/hg/pep-material/raw-file/tip/handouts/pep-ho.pdf}. But as said, you do not need to use Scala for the CWs.\footnote{Haskell, Rust, Ocaml were other languages that have
 | 
| 917 |     33 |   been used previously in CFL. I do not recommend to use Java or C or C++ for
 | 
| 830 |     34 |   writing a compiler, but if you insist, feel free. It has been done
 | 
| 917 |     35 |   before.}  
 | 
| 830 |     36 | \bigskip
 | 
| 754 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     37 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     38 | \noindent
 | 
| 917 |     39 | The other difference between the Scala I showed you in PEP is that in CFL
 | 
|  |     40 | I will use the Ammonite REPL (with underlying Scala Version 3):
 | 
| 754 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     41 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     42 | \begin{quote}
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     43 | \url{https://ammonite.io/#Ammonite-REPL}
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     44 | \end{quote}
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     45 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     46 | \noindent
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     47 | This is a drop-in replacement for the original Scala REPL and
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     48 | works very similarly, for example
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     49 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     50 | \begin{lstlisting}[language={},numbers=none,basicstyle=\ttfamily\small]
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     51 | $ amm
 | 
| 917 |     52 | Loading...
 | 
| 994 |     53 | Welcome to the Ammonite Repl 3.0.2 (Scala 3.3.5 Java 21.0.8)
 | 
| 965 |     54 | @ 1 + 2
 | 
| 754 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     55 | res0: Int = 3
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     56 | \end{lstlisting} %% $
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     57 | 
 | 
| 917 |     58 | %%\runExtCmd[redirect]{ls -la}{voss}
 | 
|  |     59 | 
 | 
|  |     60 | 
 | 
| 754 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     61 | \noindent
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     62 | Ammonite uses the same Scala compiler, just adds some useful features
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     63 | on top of it. It is quite main-stream in the Scala community and it should
 | 
| 838 |     64 | therefore be very easy for you to install \texttt{amm}. If you work under
 | 
|  |     65 | a Unix-like system, a sure way to install the right version of Ammonite
 | 
|  |     66 | is by using \texttt{curl}:
 | 
|  |     67 | 
 | 
|  |     68 | \begin{lstlisting}[numbers=none,language={},basicstyle=\ttfamily\small]
 | 
| 917 |     69 | $ curl -L https://github.com/com-lihaoyi/Ammonite/releases/\
 | 
| 994 |     70 |   download/3.0.2/3.5-3.0.2 --output amm
 | 
| 917 |     71 | \end{lstlisting} %% $  
 | 
| 838 |     72 | 
 | 
| 917 |     73 | \noindent
 | 
| 924 |     74 | This creates a file \code{amm} which before it can be run might
 | 
| 936 |     75 | need some adjustments of the permissions. Under recent versions of
 | 
|  |     76 | Windows also have \texttt{curl}, but need a slightly different call:
 | 
|  |     77 | 
 | 
|  |     78 | \begin{lstlisting}[numbers=none,language={},basicstyle=\ttfamily\small]
 | 
|  |     79 | $ curl -L https://github.com/com-lihaoyi/Ammonite/releases/\
 | 
| 994 |     80 |    download/3.0.2/3.5-3.0.2 --output amm.bat
 | 
| 936 |     81 | \end{lstlisting} %% $  
 | 
|  |     82 | 
 | 
|  |     83 | \noindent
 | 
|  |     84 | Then you need to run Ammonite with \texttt{.$\backslash$amm} and there
 | 
|  |     85 | is no need to change any permissions under Windows.  
 | 
|  |     86 | 
 | 
| 759 |     87 | The big advantage of Ammonite is that it comes with some additional
 | 
|  |     88 | libraries already built-in and also allows one to easily break up code
 | 
|  |     89 | into smaller modules. For example reading and writing files in
 | 
|  |     90 | Ammonite can be achieved with
 | 
| 754 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     91 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     92 | \begin{lstlisting}[numbers=none,language=Scala]
 | 
| 917 |     93 | scala> import os._
 | 
|  |     94 | scala> write.over(pwd / "file.name", "foo bar")  
 | 
| 754 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     95 | scala> read(pwd / "file.name")   
 | 
| 917 |     96 | res1: String = "foo bar"
 | 
| 754 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     97 | \end{lstlisting}
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     98 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     99 | \noindent
 | 
| 917 |    100 | The second line writes the string \code{"foo bar"} into the file
 | 
| 759 |    101 | \code{"file.name"}, which is located in the current working
 | 
| 994 |    102 | directory (\code{pwd}). We want to implement a compiler---therefore 
 | 
|  |    103 | reading and writing files will come in handy.
 | 
|  |    104 | 
 | 
|  |    105 | 
 | 
|  |    106 | For loading and accessing code from
 | 
| 917 |    107 | another Scala file, you can import the code into Ammonite
 | 
|  |    108 | as follows:
 | 
| 754 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    109 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    110 | \begin{lstlisting}[numbers=none,language=Scala]
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    111 | import $file.name-of-the-file
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    112 | import name-of-the-file._
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    113 | \end{lstlisting}  %% $
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    114 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    115 | \noindent
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    116 | This assumes the other Scala file is called
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    117 | \texttt{name-of-the-file.sc} and requires the file to be in the same
 | 
| 994 |    118 | directory where \texttt{amm} is working in. Again this will be very convenient 
 | 
|  |    119 | for our compiler we implement in CFL, because it allows us to easily
 | 
| 760 |    120 | break up the code into the lexer, parser and code generator.
 | 
| 754 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    121 | 
 | 
| 917 |    122 | Another handy feature of Ammonite is that you can mark functions as
 | 
|  |    123 | \texttt{@main}. For example
 | 
| 754 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    124 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    125 | \begin{lstlisting}[numbers=none,language=Scala]
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    126 | @main
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    127 | def foo() = ...
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    128 | \end{lstlisting}
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    129 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    130 | \noindent
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    131 | This means you can now call that function from the command line like
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    132 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    133 | \begin{lstlisting}[numbers=none,language=Scala]
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    134 | $ amm file.sc foo
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    135 | \end{lstlisting} %% $
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    136 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    137 | \noindent
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    138 | If you want to specify an argument on the commandline, say an int and
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    139 | a string, then you can write
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    140 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    141 | \begin{lstlisting}[numbers=none,language=Scala]
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    142 | @main
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    143 | def bar(i: Int, s: String) = ...
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    144 | \end{lstlisting}
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    145 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    146 | \noindent
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    147 | and then call
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    148 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    149 | \begin{lstlisting}[numbers=none,language=Scala]
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    150 | $ amm file.sc 42 foobar
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    151 | \end{lstlisting} %% $
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    152 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    153 | \noindent
 | 
| 917 |    154 | What is also good in Ammonite is that you can specify more than one
 | 
| 754 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    155 | function to be ``main'' and then specify on the command line which
 | 
| 760 |    156 | function you want to run as entry-point.
 | 
|  |    157 | 
 | 
|  |    158 | Another feature you might like to use is that Ammonite can ``watch'' files.
 | 
|  |    159 | This means it can automatically re-run a file when it is saved. For this
 | 
|  |    160 | you have to call \texttt{amm} with the option \texttt{-w}, as in
 | 
|  |    161 | 
 | 
|  |    162 | \begin{lstlisting}[numbers=none,language=Scala]
 | 
|  |    163 | $ amm -w file.sc
 | 
|  |    164 | \end{lstlisting} %% $
 | 
|  |    165 | 
 | 
|  |    166 | \noindent Of course this requires that you use \texttt{println} for
 | 
| 917 |    167 | inspecting any data as otherwise nothing will be displayed at the
 | 
| 994 |    168 | commandline.\medskip
 | 
| 754 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    169 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    170 | \noindent
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    171 | To sum up, Ammonite is a really useful addition to the Scala ecosystem.
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    172 | You can find more information about how to use it in the first five chapters
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    173 | of the ``Hands-on Scala'' book by Li Haoyi. These chapters are
 | 
| 936 |    174 | free and can be used as a reference, see
 | 
| 754 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    175 | 
 | 
| 936 |    176 | \begin{center}
 | 
|  |    177 | \url{https://www.handsonscala.com/part-i-introduction-to-scala.html}
 | 
|  |    178 | \end{center}
 | 
| 754 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    179 | 
 | 
| 994 |    180 | 
 | 
|  |    181 | \subsection*{Some Updates in Scala 3 and the Videos}
 | 
|  |    182 | 
 | 
|  |    183 | While Scala 2 and Scala 3 code is on the whole quite compatible, there are some
 | 
|  |    184 | corners where my Scala 3 code differs from the code shown in the videos. I am still
 | 
|  |    185 | fond of using \texttt{\{...\}} rather than Pythonesque indentation syntax. But
 | 
|  |    186 | I switched to the \texttt{enum}-syntax for abstract datatypes. Defining regular
 | 
|  |    187 | expressions in the ``old'' way can be done using abstract classes, like:
 | 
|  |    188 | 
 | 
|  |    189 | \begin{lstlisting}[language=Scala,basicstyle=\ttfamily\small]
 | 
|  |    190 | abstract class Rexp
 | 
|  |    191 | case object ZERO extends Rexp
 | 
|  |    192 | case object ONE extends Rexp
 | 
|  |    193 | case class CHAR(c: Char) extends Rexp
 | 
|  |    194 | case class ALT(r1: Rexp, r2: Rexp) extends Rexp
 | 
|  |    195 | case class SEQ(r1: Rexp, r2: Rexp) extends Rexp
 | 
|  |    196 | case class STAR(r: Rexp) extends Rexp
 | 
|  |    197 | \end{lstlisting} 
 | 
|  |    198 | 
 | 
|  |    199 | \noindent
 | 
|  |    200 | While this code still works in Scala 3 as expected, the definition can now 
 | 
|  |    201 | be simplified to:
 | 
|  |    202 | 
 | 
|  |    203 | \begin{lstlisting}[language=Scala,basicstyle=\ttfamily\small]
 | 
|  |    204 | enum Rexp {
 | 
|  |    205 |   case ZERO                     
 | 
|  |    206 |   case ONE                      
 | 
|  |    207 |   case CHAR(c: Char)            
 | 
|  |    208 |   case ALT(r1: Rexp, r2: Rexp)  
 | 
|  |    209 |   case SEQ(r1: Rexp, r2: Rexp)  
 | 
|  |    210 |   case STAR(r: Rexp)            
 | 
|  |    211 | }
 | 
|  |    212 | import Rexp._
 | 
|  |    213 | \end{lstlisting} 
 | 
|  |    214 | 
 | 
|  |    215 | \noindent
 | 
|  |    216 | Note that the syntax with \texttt{enum} needs an import, otherwise you need
 | 
|  |    217 | to refer to the constructors slightly clumsily as in \texttt{Rexp.CHAR('a')} and 
 | 
|  |    218 | so on.
 | 
|  |    219 | 
 | 
|  |    220 | Also implicits are now defined differently in Scala 3 and need to be
 | 
|  |    221 | split up into \texttt{given}s and extension methods. If you want to
 | 
|  |    222 | construct regular expressions using strings, for example \texttt{STAR("a")},
 | 
|  |    223 | then you need to declare a \texttt{given}-clause:
 | 
|  |    224 | 
 | 
|  |    225 | \begin{lstlisting}[language=Scala,basicstyle=\ttfamily\small]
 | 
|  |    226 | def charlist2rexp(s : List[Char]): Rexp = s match {
 | 
|  |    227 |   case Nil => ONE
 | 
|  |    228 |   case c::Nil => CHAR(c)
 | 
|  |    229 |   case c::s => SEQ(CHAR(c), charlist2rexp(s))
 | 
|  |    230 | }
 | 
|  |    231 | 
 | 
|  |    232 | given Conversion[String, Rexp] = (s => charlist2rexp(s.toList))
 | 
|  |    233 | \end{lstlisting} 
 | 
|  |    234 | 
 | 
|  |    235 | \noindent
 | 
|  |    236 | This uses the auxiliary function \texttt{charlist2rexp} which translates
 | 
|  |    237 | a string (list of chars) into a regular expression. The ``magic'' is then 
 | 
|  |    238 | installed in the \texttt{given}-clause which calls \texttt{charlist2rexp} 
 | 
|  |    239 | whenever a \texttt{Rexp} is expected, but a string is given.
 | 
|  |    240 | 
 | 
|  |    241 | More convenient operator syntax for regular instructions needs to be
 | 
|  |    242 | defined in Scala 3 as \emph{extension method}. For example, the shorthand-syntax
 | 
|  |    243 | for alternatives, sequences and stars needs to be defined as:
 | 
|  |    244 | 
 | 
|  |    245 | \begin{lstlisting}[language=Scala,basicstyle=\ttfamily\small]
 | 
|  |    246 | extension (r: Rexp) {
 | 
|  |    247 |   def | (s: Rexp) = ALT(r, s)
 | 
|  |    248 |   def ~ (s: Rexp) = SEQ(r, s)
 | 
|  |    249 |   def % = STAR(r)
 | 
|  |    250 | }
 | 
|  |    251 | \end{lstlisting} 
 | 
|  |    252 | 
 | 
|  |    253 | \noindent
 | 
|  |    254 | After that you can define regular expressions more conveniently
 | 
|  |    255 | as \pcode{"ab" | "bc"}, \pcode{"ab" ~ "bc"} or \pcode{"ab".\%}\;.\medskip
 | 
|  |    256 | 
 | 
|  |    257 | \noindent
 | 
|  |    258 | To sum up, it should be easy for you to translate the old syntax that
 | 
|  |    259 | is in some places used in the videos and the newer syntax used in the
 | 
|  |    260 | uploaded files. There are a few additional rough edges in the code
 | 
|  |    261 | for parsers, but I will mention them nearer the time. 
 | 
|  |    262 | 
 | 
| 754 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    263 | \end{document}
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    264 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    265 | %%% Local Variables: 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    266 | %%% mode: latex
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    267 | %%% TeX-master: t
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    268 | %%% End: 
 |