{ "cells": [ { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "
\n", "

Scala - Structuring Programs

\n", "

Marcel Lüthi
Departement of Mathematics and Computer Science

\n", "
" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Outline\n", "\n", "- Repetition: The basic building blocks\n", "- Scala - the simple parts\n", " - Objects\n", " - Groups\n", " - Collections\n", " - For-loops\n", " - Algebraic data types\n", "- Case study: Scalismo's IO Methods and ```Try``` " ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Expression, types and values\n", "\n", "![expression-types-values](./images/expression-types-values.png)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Functions and Methods\n", "\n", "\n", "Functions\n", "\n", "```scala \n", "val add = (x : Int, y : Int) => {\n", " x + y\n", "} \n", "```\n", "\n", "Methods\n", "\n", "```scala \n", "def add(x : Int, y : Int) = {\n", " x + y\n", "} \n", "```" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Classes and Objects\n", "\n", "Declaring classes\n", "\n", "```scala\n", "class Fraction(numerator : Int, denumerator : Int) {\n", " override def toString() : String = {\n", " numerator.toString() + \"/\" +denumerator.toString()\n", " }\n", "}\n", "\n", "val oneHalf = new Fraction(1, 2)\n", "oneHalf.toString()\n", "```\n", "\n", "Objects\n", "```scala\n", "object Calculator {\n", " def plus(a : Int, b : Int) = a + b \n", "}\n", "\n", "Calculator.plus(3, 4)\n", "```\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Simple Scala\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "> Simple is often erroneously mistaken for easy. \n", ">\n", "> * \"Easy\" means \"to be at hand\", \"to be approachable\".\n", "> * \"Simple\" is the opposite of \"complex\" which means \"being intertwined\", \"being tied together\".\n", ">\n", "> Rich Hickey (from the talk [Simple Made Easy](https://www.infoq.com/presentations/Simple-Made-Easy)\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# (almost) Everything is an expression\n", "\n", "* Everything evaluates to a value\n", "* Everything can be composed\n", "* Everything can be named" ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "\u001b[36mres\u001b[39m: \u001b[32mString\u001b[39m = \u001b[32m\"cde\"\u001b[39m\r\n", "\u001b[36msomeComputation\u001b[39m: \u001b[32mInt\u001b[39m = \u001b[32m8\u001b[39m\r\n", "\u001b[36mnewSeq\u001b[39m: \u001b[32mIndexedSeq\u001b[39m[\u001b[32mInt\u001b[39m] = \u001b[33mVector\u001b[39m(\u001b[32m1\u001b[39m, \u001b[32m2\u001b[39m, \u001b[32m3\u001b[39m, \u001b[32m4\u001b[39m, \u001b[32m5\u001b[39m, \u001b[32m6\u001b[39m, \u001b[32m7\u001b[39m, \u001b[32m8\u001b[39m, \u001b[32m9\u001b[39m, \u001b[32m10\u001b[39m)" ] }, "execution_count": 33, "metadata": {}, "output_type": "execute_result" } ], "source": [ "val res = if (a == 3) \"abc\" else \"cde\"\n", "\n", "val someComputation = {\n", " val a = 3 \n", " a + 5\n", "}\n", "\n", "val newSeq = for (i <- 0 until 10) yield i + 1\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Everything is an object\n", "\n", "* We always interact with any value by\n", " * Calling methods\n", " * Accessing fields\n", " \n", "Example: \n", "```scala \n", "1 + 3\n", "```\n", "\n", "* 1 is object\n", "* ```+``` is method\n", "* 3 is Argument\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Mini exercises\n", "\n", "\n", "Create a class Complex for representing complex numbers\n", "\n", "```scala\n", "case class Complex(re : Double, imag : Double)\n", "``` \n", "\n", "* Implement a method called ```+``` to add two complex numbers\n", "* Try out the method:\n", " * Do you need the ```.``` to call it?\n", " * Do you need the paranthesis?\n", "\n", "* Implement a method called ```#*--!```\n", "\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "// type your solution here" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Groups\n", "\n", "* Everything can be grouped and nested\n", "* Static uniform scoping rules\n", " * Allows naming of thing\n", " * Allows keeping local things in local context\n" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "defined \u001b[32mfunction\u001b[39m \u001b[36mfoo\u001b[39m" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "\n", "def foo() : Unit = {\n", " \n", " import collection.immutable.List\n", " \n", " case class KeyValue(key : String, value : Int)\n", " \n", " val list = List(KeyValue(\"A\", 3), KeyValue(\"B\", 2))\n", " def keyIsA(kv : KeyValue) : Boolean = { kv.key == \"A\" }\n", " \n", " list.count(keyIsA)\n", "}" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Collections\n", "\n", "* Collections aggregate data\n", "* Transformed to manipulate data\n", " * updates not possible with default collections\n", "* Uniform interface - Learn once, use everywhere" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Collections - Basic operations" ] }, { "cell_type": "code", "execution_count": 19, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "\u001b[36mpeople\u001b[39m: \u001b[32mSeq\u001b[39m[\u001b[32mString\u001b[39m] = \u001b[33mList\u001b[39m(\u001b[32m\"bob martin\"\u001b[39m, \u001b[32m\"john doe\"\u001b[39m, \u001b[32m\"william tell\"\u001b[39m)" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "val people = Seq(\"bob martin\", \"john doe\", \"william tell\")" ] }, { "cell_type": "code", "execution_count": 20, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "\u001b[36mres19\u001b[39m: \u001b[32mSeq\u001b[39m[\u001b[32mString\u001b[39m] = \u001b[33mList\u001b[39m(\u001b[32m\"BOB MARTIN\"\u001b[39m, \u001b[32m\"JOHN DOE\"\u001b[39m, \u001b[32m\"WILLIAM TELL\"\u001b[39m)" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "people.map(name => name.toUpperCase)" ] }, { "cell_type": "code", "execution_count": 21, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "\u001b[36mres20\u001b[39m: \u001b[32mSeq\u001b[39m[\u001b[32mString\u001b[39m] = \u001b[33mList\u001b[39m(\u001b[32m\"bob martin\"\u001b[39m)" ] }, "execution_count": 21, "metadata": {}, "output_type": "execute_result" } ], "source": [ "people.filter(name => name.startsWith(\"b\"))" ] }, { "cell_type": "code", "execution_count": 23, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "\u001b[36mres22\u001b[39m: \u001b[32mSeq\u001b[39m[\u001b[32mString\u001b[39m] = \u001b[33mList\u001b[39m(\u001b[32m\"bob\"\u001b[39m, \u001b[32m\"martin\"\u001b[39m, \u001b[32m\"john\"\u001b[39m, \u001b[32m\"doe\"\u001b[39m, \u001b[32m\"william\"\u001b[39m, \u001b[32m\"tell\"\u001b[39m)" ] }, "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ "people.flatMap(name => name.split(\" \"))" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Tuples, zip and unzip\n", "\n", "* Tuples represent a immutable sequence of fixed length" ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "\u001b[36mt\u001b[39m: (\u001b[32mInt\u001b[39m, \u001b[32mString\u001b[39m) = (\u001b[32m1\u001b[39m, \u001b[32m\"abc\"\u001b[39m)" ] }, "execution_count": 29, "metadata": {}, "output_type": "execute_result" } ], "source": [ "val t : Tuple2[Int, String] = (1, \"abc\")" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "* Zip creates a sequence of tuples from two sequences \n", "* Unzip create two sequences from a sequence of tuples" ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "zipped list: List((1,a), (2,b), (3,c), (4,d))\n" ] }, { "data": { "text/plain": [ "\u001b[36ma\u001b[39m: \u001b[32mSeq\u001b[39m[\u001b[32mInt\u001b[39m] = \u001b[33mList\u001b[39m(\u001b[32m1\u001b[39m, \u001b[32m2\u001b[39m, \u001b[32m3\u001b[39m, \u001b[32m4\u001b[39m)\r\n", "\u001b[36mb\u001b[39m: \u001b[32mSeq\u001b[39m[\u001b[32mString\u001b[39m] = \u001b[33mList\u001b[39m(\u001b[32m\"a\"\u001b[39m, \u001b[32m\"b\"\u001b[39m, \u001b[32m\"c\"\u001b[39m, \u001b[32m\"d\"\u001b[39m)\r\n", "\u001b[36mzippedSeq\u001b[39m: \u001b[32mSeq\u001b[39m[(\u001b[32mInt\u001b[39m, \u001b[32mString\u001b[39m)] = \u001b[33mList\u001b[39m((\u001b[32m1\u001b[39m, \u001b[32m\"a\"\u001b[39m), (\u001b[32m2\u001b[39m, \u001b[32m\"b\"\u001b[39m), (\u001b[32m3\u001b[39m, \u001b[32m\"c\"\u001b[39m), (\u001b[32m4\u001b[39m, \u001b[32m\"d\"\u001b[39m))\r\n", "\u001b[36maUnzipped\u001b[39m: \u001b[32mSeq\u001b[39m[\u001b[32mInt\u001b[39m] = \u001b[33mList\u001b[39m(\u001b[32m1\u001b[39m, \u001b[32m2\u001b[39m, \u001b[32m3\u001b[39m, \u001b[32m4\u001b[39m)\r\n", "\u001b[36mbUnzipped\u001b[39m: \u001b[32mSeq\u001b[39m[\u001b[32mString\u001b[39m] = \u001b[33mList\u001b[39m(\u001b[32m\"a\"\u001b[39m, \u001b[32m\"b\"\u001b[39m, \u001b[32m\"c\"\u001b[39m, \u001b[32m\"d\"\u001b[39m)" ] }, "execution_count": 31, "metadata": {}, "output_type": "execute_result" } ], "source": [ "val a = Seq(1, 2, 3, 4)\n", "val b = Seq(\"a\", \"b\", \"c\", \"d\")\n", "\n", "val zippedSeq : Seq[(Int, String)] = a.zip(b)\n", "println(\"zipped list: \" +zippedSeq)\n", "\n", "val (aUnzipped, bUnzipped) : (Seq[Int], Seq[String]) = zippedSeq.unzip" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Mini exercise\n", "\n", "* Create a sequence of values from 1 to 10\n", "* Double each value in the sequence\n", "* Filter out the values that can be divided by 7\n", "* Create a sequence of values like this:\n", " ```1, 2, 3, 2, 3, 4, 3, 4, 5, ...```\n", "* Create the cartesian product of the numbers 1 to 10 using only map and flatmap\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# For - loops\n", "\n", "> Scala has also for loops" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "for (i <- 0 until 10) {\n", " print(i + \" \")\n", "}" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "val evenNumbers = for (i <- 0 until 10) yield {\n", " i * 2\n", "}" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Not your father's for loops\n", "\n", "> For loops are only syntactic sugar\n", "\n", "The two expressions are the same:\n", "```scala\n", "(0 until 10).map(i => i * 2)\n", "```\n", "```scala\n", "for (i <- 0 until 10) yield {\n", " i * 2\n", "}\n", "```\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Not your father's for loops\n", "\n", "> For loops are only syntactic sugar\n", "\n", "The two expressions are the same:\n", "```scala\n", "(0 until 10).filter(i => i % 2 == 0)\n", "```\n", "```scala\n", "for (i <- 0 until 10 if i % 2 == 0) yield {\n", " i\n", "}\n", "```\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Not your father's for loops\n", "\n", "> For loops are only syntactic sugar\n", "\n", "The two expressions are the same:\n", "```scala\n", "(0 until 10).flatMap(i =>(i until i + 2))\n", "```\n", "```scala\n", "for (i <- (0 until 10; \n", " iSeq <- i until i + 2) yield iSeq\n", "```\n", "\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Not your father's for loops\n", "\n", "> For loops are only syntactic sugar\n", "\n", "Makes complicated expressions look simple\n", "```scala\n", "for (i <- 0 until 10;\n", " j <- 0 until 10;\n", " if (i + j) == 7) yield (i , j)\n", "```\n", "\n" ] } ], "metadata": { "celltoolbar": "Slideshow", "kernelspec": { "display_name": "Scala", "language": "scala", "name": "scala" }, "language_info": { "codemirror_mode": "text/x-scala", "file_extension": ".sc", "mimetype": "text/x-scala", "name": "scala", "nbconvert_exporter": "script", "version": "2.13.5" } }, "nbformat": 4, "nbformat_minor": 2 }