{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "

Previous

\n", "

Next

\n", "

Tour of Scala

\n", "
\n", "\n", "# Multiple Parameter Lists (Currying)\n", "\n", "Methods may define multiple parameter lists. When a method is called with a fewer number of parameter lists, then this will yield a function taking the missing parameter lists as its arguments. This is formally known as [currying](https://en.wikipedia.org/wiki/Currying).\n", "\n", "Here is an example, defined in [Traversable](https://docs.scala-lang.org/overviews/collections/trait-traversable.html) trait from Scala collections:" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "```scala\n", "def foldLeft[B](z: B)(op: (B, A) => B): B\n", "```\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`foldLeft` applies a binary operator `op` to an initial value `z` and all elements of this traversable, going left to right. Shown below is an example of its usage. \n", "\n", "Starting with an initial value of 0, `foldLeft` here applies the function `(m, n) => m + n` to each element in the List and the previous accumulated value." ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "attributes": { "classes": [ "tut" ], "id": "" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "55" ] }, { "data": { "text/plain": [ "\u001b[36mnumbers\u001b[39m: \u001b[32mList\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, \u001b[32m5\u001b[39m, \u001b[32m6\u001b[39m, \u001b[32m7\u001b[39m, \u001b[32m8\u001b[39m, \u001b[32m9\u001b[39m, \u001b[32m10\u001b[39m)\n", "\u001b[36mres\u001b[39m: \u001b[32mInt\u001b[39m = \u001b[32m55\u001b[39m" ] }, "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ "val numbers = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)\n", "val res = numbers.foldLeft(0)((m, n) => m + n)\n", "print(res) // 55" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Multiple parameter lists have a more verbose invocation syntax; and hence should be used sparingly. Suggested use cases include:\n", "\n", "#### Single functional parameter\n", " In case of a single functional parameter, like `op` in the case of `foldLeft` above, multiple parameter lists allow a concise syntax to pass an anonymous function to the method. Without multiple parameter lists, the code would look like this:" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "attributes": { "classes": [ "tut" ], "id": "" } }, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "cmd1.sc:1: missing argument list for method foldLeft in trait LinearSeqOptimized\n", "Unapplied methods are only converted to functions when a function type is expected.\n", "You can make this conversion explicit by writing `foldLeft _` or `foldLeft(_)(_)` instead of `foldLeft`.\n", "val res1 = numbers.foldLeft(0, {(m: Int, n: Int) => m + n})\n", " ^Compilation Failed" ] }, { "ename": "", "evalue": "", "output_type": "error", "traceback": [ "Compilation Failed" ] } ], "source": [ "numbers.foldLeft(0, {(m: Int, n: Int) => m + n})" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note that the use of multiple parameter lists here also allows us to take advantage of Scala type inference to make the code more concise as shown below; which would not be possible in a non-curried definition." ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "attributes": { "classes": [ "tut" ], "id": "" } }, "outputs": [ { "data": { "text/plain": [ "\u001b[36mres1\u001b[39m: \u001b[32mInt\u001b[39m = \u001b[32m55\u001b[39m" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "numbers.foldLeft(0)(_ + _)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Above statement `numbers.foldLeft(0)(_ + _)` allows us to fix the parameter `z` and pass around a partial function and reuse it as shown below:" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "attributes": { "classes": [ "tut" ], "id": "" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "List(1, 4, 9, 16, 25, 36, 49, 64, 81, 100)List(1, 8, 27, 64, 125, 216, 343, 512, 729, 1000)" ] }, { "data": { "text/plain": [ "\u001b[36mnumbers\u001b[39m: \u001b[32mList\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, \u001b[32m5\u001b[39m, \u001b[32m6\u001b[39m, \u001b[32m7\u001b[39m, \u001b[32m8\u001b[39m, \u001b[32m9\u001b[39m, \u001b[32m10\u001b[39m)\n", "\u001b[36mnumberFunc\u001b[39m: (\u001b[32mList\u001b[39m[\u001b[32mInt\u001b[39m], \u001b[32mInt\u001b[39m) => \u001b[32mList\u001b[39m[\u001b[32mInt\u001b[39m] => \u001b[32mList\u001b[39m[\u001b[32mInt\u001b[39m] = ammonite.$sess.cmd2$Helper$$Lambda$2487/1839209380@62413d6c\n", "\u001b[36msquares\u001b[39m: \u001b[32mList\u001b[39m[\u001b[32mInt\u001b[39m] = \u001b[33mList\u001b[39m(\u001b[32m1\u001b[39m, \u001b[32m4\u001b[39m, \u001b[32m9\u001b[39m, \u001b[32m16\u001b[39m, \u001b[32m25\u001b[39m, \u001b[32m36\u001b[39m, \u001b[32m49\u001b[39m, \u001b[32m64\u001b[39m, \u001b[32m81\u001b[39m, \u001b[32m100\u001b[39m)\n", "\u001b[36mcubes\u001b[39m: \u001b[32mList\u001b[39m[\u001b[32mInt\u001b[39m] = \u001b[33mList\u001b[39m(\u001b[32m1\u001b[39m, \u001b[32m8\u001b[39m, \u001b[32m27\u001b[39m, \u001b[32m64\u001b[39m, \u001b[32m125\u001b[39m, \u001b[32m216\u001b[39m, \u001b[32m343\u001b[39m, \u001b[32m512\u001b[39m, \u001b[32m729\u001b[39m, \u001b[32m1000\u001b[39m)" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "val numbers = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)\n", "val numberFunc = numbers.foldLeft(List[Int]())_\n", "\n", "val squares = numberFunc((xs, x) => xs:+ x*x)\n", "print(squares.toString()) // List(1, 4, 9, 16, 25, 36, 49, 64, 81, 100)\n", "\n", "val cubes = numberFunc((xs, x) => xs:+ x*x*x)\n", "print(cubes.toString()) // List(1, 8, 27, 64, 125, 216, 343, 512, 729, 1000)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Finally, `foldLeft` and `foldRight` can be used in any of the following terms," ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "attributes": { "classes": [ "tut" ], "id": "" } }, "outputs": [ { "data": { "text/plain": [ "\u001b[36mnumbers\u001b[39m: \u001b[32mList\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, \u001b[32m5\u001b[39m, \u001b[32m6\u001b[39m, \u001b[32m7\u001b[39m, \u001b[32m8\u001b[39m, \u001b[32m9\u001b[39m, \u001b[32m10\u001b[39m)\n", "\u001b[36mres3_1\u001b[39m: \u001b[32mInt\u001b[39m = \u001b[32m55\u001b[39m\n", "\u001b[36mres3_2\u001b[39m: \u001b[32mInt\u001b[39m = \u001b[32m55\u001b[39m\n", "\u001b[36mres3_3\u001b[39m: \u001b[32mInt\u001b[39m = \u001b[32m55\u001b[39m\n", "\u001b[36mres3_4\u001b[39m: \u001b[32mInt\u001b[39m = \u001b[32m55\u001b[39m\n", "\u001b[36mres3_5\u001b[39m: \u001b[32mInt\u001b[39m = \u001b[32m55\u001b[39m\n", "\u001b[36mres3_6\u001b[39m: \u001b[32mInt\u001b[39m = \u001b[32m55\u001b[39m" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "val numbers = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)\n", "\n", "numbers.foldLeft(0)((sum, item) => sum + item) // Generic Form\n", "numbers.foldRight(0)((sum, item) => sum + item) // Generic Form\n", "\n", "numbers.foldLeft(0)(_+_) // Curried Form\n", "numbers.foldRight(0)(_+_) // Curried Form\n", "\n", "(0 /: numbers)(_+_) // Used in place of foldLeft\n", "(numbers :\\ 0)(_+_) // Used in place of foldRight" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Implicit parameters\n", "To specify certain parameters in a parameter list as `implicit`, multiple parameter lists should be used. An example of this is:" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "```scala\n", "def execute(arg: Int)(implicit ec: ExecutionContext) = ???\n", "```\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

Previous

\n", "

Next

\n", "

Tour of Scala

\n", "
" ] } ], "metadata": { "kernelspec": { "display_name": "Scala (2.13)", "language": "scala", "name": "scala213" }, "language_info": { "codemirror_mode": "text/x-scala", "file_extension": ".scala", "mimetype": "text/x-scala", "name": "scala", "nbconvert_exporter": "script", "version": "2.13.1" } }, "nbformat": 4, "nbformat_minor": 4 }