{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Différents modes d'évaluation\n", "\n", "Scala donne le choix entre plusieurs sémantiques en ce qui concerne l'évaluation des paramètres de fonctions.\n", "On distingue les appels par nom (ou par référence), et les appels par valeur.\n", "\n", "Dans un appel par valeur, l'argument est évalué avant l'exécution de la fonction.\n", "Dans un appel par nom, l'argument est manipulé symboliquement, son évaluation ne se faisant qu'en dernier recours." ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "eval x\n", "eval y\n", "myand1\n", "myand2\n", "eval x\n" ] }, { "data": { "text/plain": [ "false" ] }, "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ "def x() = { println(\"eval x\"); false }\n", "def y() = { println(\"eval y\"); false }\n", "\n", "// x and y have type Boolean\n", "def myand1(x: Boolean, y: Boolean) = { println(\"myand1\"); x && y }\n", "// x and y, if evaluated, both yield a Boolean\n", "// This is the syntax of the call-by-name semantics\n", "def myand2(x: => Boolean, y: => Boolean) = { println(\"myand2\"); x && y }\n", "\n", "// x and y are called *before* the beginning of myand1\n", "myand1(x(), y())\n", "// x and y are called only when needed; since x returns false, y needs not be evaluated\n", "myand2(x(), y())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Généricité\n", "\n", "On peut aussi paramétrer les classes (et les fonctions) par des types, permettant plus de généricité.\n", "C'est un mécanisme similaire (dans sa fonctionnalité) aux templates C++ ou aux types génériques en Java." ] }, { "cell_type": "code", "execution_count": 14, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "Name: Compile Error\n", "Message: :31: error: reference to MyList is ambiguous;\n", "it is imported twice in the same scope by\n", "import INSTANCE.MyList\n", "and import INSTANCE.MyList\n", " def myListLength[T]: MyList[T] => Int = {\n", " ^\n", ":32: error: reference to MyNil is ambiguous;\n", "it is imported twice in the same scope by\n", "import INSTANCE.MyNil\n", "and import INSTANCE.MyNil\n", " case MyNil() => 0\n", " ^\n", ":33: error: reference to MyCons is ambiguous;\n", "it is imported twice in the same scope by\n", "import INSTANCE.MyCons\n", "and import INSTANCE.MyCons\n", " case MyCons(_, t) => myListLength(t) + 1\n", " ^\n", ":33: error: not found: value t\n", " case MyCons(_, t) => myListLength(t) + 1\n", " ^\n", "StackTrace: " ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "// a generic class hierarchy\n", "abstract class MyList[T]\n", "case class MyNil[T] extends MyList[T]\n", "case class MyCons[T](val head: T, val tail: MyList[T]) extends MyList[T] \n", "\n", "// a generic function\n", "def myListLength[T]: MyList[T] => Int = {\n", " case MyNil() => 0\n", " case MyCons(_, t) => myListLength(t) + 1\n", "}\n", "\n", "val l1 = MyCons(1, MyCons(2, MyCons(3, MyNil())))\n", "myListLength[Int](l1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Quand il n'y a pas de risque d'ambiguïté, on peut se permettre d'omettre le paramètre de type." ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "3" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "listLength(l1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Cette généricité peut se révéler très utile pour définir des structures de données dans des bibliothèques.\n", "\n", "En exercice, vous pouvez reprendre l'implémentation des ensembles d'ensembles fonctionnels et les rendre génériques." ] } ], "metadata": { "kernelspec": { "display_name": "Apache Toree - Scala", "language": "scala", "name": "apache_toree_scala" }, "language_info": { "name": "scala", "version": "2.10.4" } }, "nbformat": 4, "nbformat_minor": 2 }