.. _FP2: .. raw:: html .. |--| unicode:: U+2013 .. en dash .. |---| unicode:: U+2014 .. em dash, trimming surrounding whitespace :trim: .. odsalink:: AV/PL/FP/FP2CON.css .. This file is part of the OpenDSA eTextbook project. See .. http://algoviz.org/OpenDSA for more details. .. Copyright (c) 2012-13 by the OpenDSA Project Contributors, and .. distributed under an MIT open source license. .. avmetadata:: :author: David Furcy and Tom Naps ============================================================================== Functional Programming - Developing basic, recursive list-processing functions ============================================================================== Recursive List Processing (1) ----------------------------- In the previous section, we introduced three predicates that are part of the *fp* module -- *isEq*, *isZero*, and *isNull*. We will now introduce some additional predicates and arithmetic functions that we will then use to write recursive list-processing functions, including ``sum``, ``isMember``, ``removeFirst``, and ``subst``. First, to check whether something is a list or not, you must use the ``isList`` function:: > fp.isList( [ ] ) true > fp.isList( [1,2,3] ) true > fp.isList( 1 ) false Second, the two helper functions ``add`` and ``sub`` perform the addition and subtraction, respectively, of their two integer arguments:: > fp.add(2,3) 5 > fp.sub(2,3) -1 Third, the two predicates ``isLT`` and ``isGT`` test whether their first argument is less than or greater than their second argument, respectively:: > fp.isGT(2,3) false > fp.isLT(2,3) true We're now ready to write a recursive ``sum`` function that takes in an integer list and returns the sum of all of the values in the input list. :: > var fp = require('./fp') > sum( [ 1, 2, 3 ] ) 6 > sum( [ ] ) 0 > sum( [ 1, -2, 3, -4] ) -2 When we design a recursive algorithm, we must keep in mind the recursive BNF definition of integer lists: .. math:: \begin{eqnarray*} &::=& \epsilon \\ & | & \\ \end{eqnarray*} Following the two paths for a ** in this grammar -- one for the empty list and one for a non-empty list leads us to structure a *sum* function as shown below. Think about how to complete this function. .. inlineav:: FP2Code1CON ss :points: 0.0 :required: False :threshold: 1.0 :long_name: Illustrate Simple Recursion On List To Return Numeric Value :output: show Then try the following review problem, which uses similar recursive list-processing logic. Note that this problem is randomized. You must solve it correctly three times in a row to earn the point associated with it. .. avembed:: Exercises/PL/RecListProc1.html ka :module: FP2 :points: 1.0 :required: True :threshold: 3 :exer_opts: JXOP-debug=true&JOP-lang=en&JXOP-code=java :long_name: Recursion on Flat lists 1 Recursive List Processing (2) ----------------------------- Next consider a function *isMember* that takes in an integer *n* and an integer list *ns* and returns true if and only if its first argument is a member of the second argument:: > var fp = require('./fp') > isMember( 2, [ 1, 2, 3 ] ) true > isMember( 4, [ 1, 2, 3 ] ) false > isMember( 2, [ 1, [ 2, 3 ] ] ) false Note that the second argument in the last call above is not an integer list. Keep in mind the recursive definition of integer lists: .. math:: \begin{eqnarray*} &::=& \epsilon \\ & | & \\ \end{eqnarray*} Following that recursive definition we design a recursive algorithm for *isMember* using the template provided in the first slide below. .. inlineav:: FP2Code2CON ss :points: 0.0 :required: False :threshold: 1.0 :long_name: Illustrate Simple Recursion On List To Define IsMember :output: show Using a recursive pattern similar to that for *isMember*, think about how to design a similar list-processing function *removeFirst* that takes in an integer :math:`n` and an integer list :math:`l` and returns a list identical to :math:`l` but with the first occurrence of :math:`n` removed:: > var fp = require('./fp') > removeFirst(3,[1,2,3]) [ 1, 2 ] > removeFirst(4,[1,2,3]) [ 1, 2, 3 ] > removeFirst(2,[1,2,3,2]) [ 1, 3, 2 ] Once you have the correct logic for *removeFirst*, consider the following review problem, which asks you to slightly modify *removeFirst*. .. avembed:: Exercises/PL/RecListProc2.html ka :module: FP2 :points: 1.0 :required: True :threshold: 1 :exer_opts: JXOP-debug=true&JOP-lang=en&JXOP-code=java :long_name: Recursion on Flat Lists 2 .. _subst: Recursive List Processing (3) ----------------------------- As a final example in this section consider a function that takes in two integers :math:`n` (for ’new’) and :math:`o` (for ’old’) and an integer list :math:`l` and returns a list identical to :math:`l` except that all occurrences of :math:`o` in :math:`l` have been replaced by :math:`n`:: > var fp = require('./fp') > subst(10,1,[1,2,3,2,1]) [ 10, 2, 3, 2, 10 ] > subst(50,5,[1,2,3]) [ 1, 2, 3 ] > subst(10,1,[[1,2],3]) [ [ 1, 2 ], 3 ] Note that we stretched the semantics of the *subst* function a bit since the third argument in the last call above is not an integer list. Again the template for the *subst* function follows the pattern established by the BNF grammar for a **. .. inlineav:: FP2Code3CON ss :points: 0.0 :required: False :threshold: 1.0 :long_name: Illustrate Simple Recursion On List To Do Substitution :output: show Now that we have established the correct logic for this function, consider the final review problem for this section, which asks you to slightly modify the ``subst`` function. .. avembed:: Exercises/PL/RecListProc3.html ka :module: FP2 :points: 1.0 :required: True :threshold: 1 :exer_opts: JXOP-debug=true&JOP-lang=en&JXOP-code=java :long_name: Recursion on Flat Lists 3 .. odsascript:: AV/PL/FP/FP2Code1CON.js .. odsascript:: AV/PL/FP/FP2Code2CON.js .. odsascript:: AV/PL/FP/FP2Code3CON.js