{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Functional Programming\n", "One of the most popular programming paradigms is FP. \n", "In this lecture, we show how we can use Python to carry out some basic FP.\n", "\n", "**Created and updated by** John C. S. Lui on October 12, 2020.\n", "\n", "**Important note:** *If you want to use and modify this notebook file, please acknowledge the author.*" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Functional programming\n", "\n", "- Treat input as \"set\"\n", "- Define operations we want to do for each element of the set\n", "\n", "In functional programming, there are two important concepts:\n", " - iterator\n", " - passing function as parameter to another function\n", "\n", "So let us go over **iterator** first." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "## Iterators: list\n", "for x in [1,2,3,4,5]:\n", " print(\"Element is: \", x)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "## Iteators: character string\n", "for c in \"John is a jerk!!!\":\n", " print (\"Char. is: \", c)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Iterators: tuple\n", "for x in (1,2,3,4,5):\n", " print ('x is:', x)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Iterators: dictionary\n", "\n", "# When we use with dictionary, it loops over the keys of the dictionary\n", "for key in {\"k1\": 'value1', \"k2\": 'value2', \"k3\": 15}:\n", " print (\"key is: \", key)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Iterators\n", "\n", "- list, character strings, tuple and dictionary are all **iterable objects**.\n", "\n", "- A function *func* takes an iterable object and returns an iterator." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "iter_obj = iter([1,2,3,4,5]) #iter_obj is an iterable object\n", "print(iter_obj)\n", "print([1,2,3,4,5])\n", "\n", "# iter_obj.next() # display next item\n", "print(next(iter_obj), next(iter_obj), next(iter_obj))\n", "print(next(iter_obj),next(iter_obj))\n", "\n", "# can't access the next item\n", "# next(iter_obj)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Python Function\n", "- Name of a function is just a *reference* to an object representing that function\n", "- We can assign that function to another variable\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import math\n", "\n", "mySqrt = math.sqrt # assign my math.sqrt function to the variable mySqrt\n", "mySqrt(4.0)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- If a variable can be a reference to a function\n", "- And we can pass variable as a parameter to a function\n", "- This means we can also pass a function (or variable) as a parameter to another function !!!\n", "\n", "For detail, please the document:\n", "http://python-history.blogspot.com/2009/02/first-class-everything.html\n", "\n", "Why is this **important**? Because in functional programming, we need the concept of:\n", "- iterator\n", "- passing function as parameter" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Transformation\n", "\n", "Often, our variables (or data) are represented using list, tuple or dictionary.
\n", "We may want to carry out some *transformation* for all or a subet of elements in the variable.
\n", "This can be achieved via \n", "- mapping\n", "- filtering\n", "- reduction (for Python 2.x)\n", "\n", "Let's illustrate the *map()* function first.
\n", "\n", "The general syntax is:
\n", "             % *map(func, seq)*
\n", "where *func* is a pre-defined function which will operate on **each element** of the *seq* sequence (e.g., list).\n", "\n", "Note that in Python 2.x, map returns a list, where each element of the result list is the result
\n", "of the function *func* applied on the corresponding element of the list or tuple *seq*.
\n", "With Python 3, *map()* returns an * **iterator** *." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# we have a list of integer and we want to multiply each elements in the list by 2 and add 1 to it.\n", "\n", "# First, define a function\n", "def map_func1(x): \n", " return x*2 + 1\n", "\n", "my_variable = [1,2,3,4,5] # define a list\n", "\n", "#apply map_func1 to my_variable, and convert the result to a list\n", "print(\"my_variable is : \", my_variable)\n", "\n", "\n", "my_variable = list (map(map_func1, range(0,11)))\n", "print(\"my_variable is now : \", my_variable)\n", "\n", "my_variable = [ x+1 for x in map(map_func1, range(0,11)) ] # using list compreshension\n", "print(\"my_variable is really :\", my_variable)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "You can put **more than one input (or sequence)** as arguments." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# define function\n", "def my_add (x,y): \n", " return x+y\n", "\n", "my_variable = list(map(my_add, range(0,10), range(0,10)))\n", "print(my_variable)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's see how *filter()* function works.\n", "\n", "The general syntax is:
\n", "             % *filter (func, seq)* \n", " \n", "where each element in the *seq* will be passed to the *func* to check the **boolean condition**. If it is satisfied, the element will be returned.
\n", "\n", "Hence, all elements will be returned as an **iterator** ." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# define a filter function\n", "def my_func1(x): return x % 3 == 0 or x % 5 == 0 # return True or False\n", "\n", "def my_func2(x): return (x+1)%2 == 0 # return True or False\n", "\n", "my_variable = list(filter(my_func1, range(1,25)))\n", "print(\"1. my_variable = \", my_variable)\n", "\n", "my_variable = [ x for x in filter(my_func2, range(1,25))] # use list comprehension !!!!\n", "print(\"2. my_variable = \", my_variable)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's see how *reduce()* function works in Python 2.x.\n", "\n", "The general syntax is:
\n", "             % *reduce (func, seq)* \n", " \n", "returns a **single value** constructed by calling the *func* function on the
\n", "first two items of the *seq*, then the result and the next item of *seq*
\n", "will again be applied to the *func* function, and so on. Let's see an example (in Python 2.x):\n", "\n", "        >>> def add(x,y): return x+y
\n", "        >>> reduce (add, range(1,11))     # this will return 55 in Python 2.x\n", "\n", "For Python 3.x, we have to first *import* the functools package of reduce:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from functools import reduce\n", "\n", "#define a reduce function\n", "def my_add(x,y): return x+y\n", "\n", "reduce(my_add, range(1,11))\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Lambda function\n", "\n", "The lambda operator or lambda function is a way to create small *anonymous* functions, i.e. \n", "functions without a name.
\n", "\n", "The general syntax of a *lambda* function is quite simple: \n", "\n", "        >>> *lambda argument_list: expression*\n", "\n", "The argument list consists of a comma separated list of arguments, and the expression is
\n", "an arithmetic expression using these arguments. One can assign the function to a variable to give it a name.\n", "\n", "Let's illustrate." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# define a function\n", "def sum(x,y): return x + y\n", "\n", "# an alternate way to write this small function is via lambda\n", "sum1 = lambda x, y : x + y\n", "\n", "print (sum (3,4))\n", "print (sum1(3,4))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Combining lambda and map/filter function\n", "\n", "Let's see how can use lambda with other map/filter functions" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# use of lambda function\n", "my_variable1 = list(map(lambda x,y: x+y, range(0,10), range(0,10)))\n", "print (\"my_variable1 = \", my_variable1)\n", "\n", "# use lambda and list comprehension\n", "my_variable2 = [x for x in map(lambda x,y: x+y, range(0,10), range(0,10))] \n", "print(\"my_variable2 = \", my_variable2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## List comprehension\n", "\n", "General syntax:\n", "\n", "        [ *expression* **for** *var* **in** *iterator or list* **if** expression ]\n", "\n", "- **if** part is optional\n", "- Each element in the list (or iterator) is examined by the **if** statement\n", "- If elemnet passes **if** check, then *expression* is evaluated and result will be added to the list (or iterator)\n", "\n", "Let's illustrate." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# define a list\n", "a_list = [1,2,3,4,5]\n", "print(\"The result is: \", [x*2 for x in a_list if x<4])" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# define a dictionary\n", "my_dictionary = {1:'john', 2:'jack', 3:'alice', 4:'helen'}\n", "\n", "a_list = [my_dictionary[i].title() for i in my_dictionary.keys()]\n", "print('a_list = ', a_list)\n", "\n", "a_list = [my_dictionary[i].title() for i in my_dictionary.keys() if i %2 == 0]\n", "print('a_list = ', a_list)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.8.3" } }, "nbformat": 4, "nbformat_minor": 2 }