ENGLISH:
Currying:
- fCC paraphrase: The 'arity' of a function is the number of arguments
it requires. 'Currying' a function means to convert a function of N arity
into N functions of arity 1. In other words, currying restructures a
function so that the function takes one argument, then returns another
function that takes the next argument, and so on.
- Gandolfo's definition: "Currying is when you create a function that can
later be called multiple times with different arguments."
Composing:
- Gandolfo's definition: "Composing is, essentially, when you take two
functions and combine them."
Closure:
- From this article https://dmitripavlutin.com/simple-explanation-of-javascript-closures/:
- "The closure is a function that accesses its lexical scope even [when it's] executed
outside of its lexical scope."
- "...the closure is a function that captures variables from outer function(s)."
- "Finally, a closure is a function that captures variables from its lexical scope. In
simple words, the closure (which is a function) remembers the variables from the place
where it (the function (the closure)) is defined, no matter where it is executed."
- From this https://eloquentjavascript.net/03_functions.html:
- "Thinking about programs like this takes some practice. A good mental model is to think
of function values as containing both the code in their body and the environment in which
they are created. When called, the function body sees the environment in which it was
created, not the environment in which it is called."
- Robert paraphrase:
- Even though the call stack is cleared after the function runs, any variable still needed
for reference is "remembered".
CODE:// JS// Currying (fCC example 1)functionunCurried(x,y){returnx+y}console.log(unCurried(1,2))// 3functioncurried(x){returnfunction(y){returnx+y}}// more concise way: const curried = x => y => x + yconsole.log(curried(1)(2))// 3// Currying (fCC example 2)functionadd(x){returnfunction(y){returnfunction(z){returnx+y+z}}}console.log(add(10)(20)(30))// 60//-------------------------------------------------------------------// JS// Closure example 1constmyAlert=()=>{constx="Help! I think I found a clue!"constalerter=()=>{alert(x)}alerter()}myAlert()// Help! I think I found a clue!// (but instead of being logged, it's a window that appears, due to how 'alert()' works).// Closure example 2constmyAlert=()=>{constx="Help! I think I found a clue!"constalerter=()=>{alert(x)}setTimeout(alerter,1000)console.log('Does the alert or log happen first?')// Does the alert or log happen first?}myAlert()// Help! I think I found a clue!// (but instead of being logged, it's a window that appears, due to how 'alert()' works).// Note that 'setTimeout...' is called before 'console.log...', as you'd think, but is not// visible because it goes away "deep into browser land" for 1 second, and, during this// time, 'Does the alert or log happen first?' is logged.// Closure example 3constmyAlert=()=>{constx="Help! I think I found a clue!"letcount=0constalerter=()=>{alert(`${x}${++count}`)}returnalerter// This is returning whatever value is held in 'alerter',...// ...and the value that is held is the body of a function,...}constfuncAlert=myAlert()// ...so the body of the function is now stored in 'funcAlert',...constfuncAlert2=myAlert()funcAlert()// ...and now 'funcAlert' is called, and logged is: Help! I think I found a clue! 1// (but instead of being logged, it's a window that appears, due to how 'alert()' works).// And as you'd expect, 'funcAlert()' makes the alert appear, but actually RETURNS 'undefined'.funcAlert()// Help! I think I found a clue! 2// ('2' this time because here we're not re-creating the whole "execution context" (i.e., from// 'const myAlert'), but are entering straight into the 'alerter' function body, and 'count'// was already storing '1' from the first 'funcAlert' call.)funcAlert2()// Help! I think I found a clue! 1// ('1' because a new "execution context" was created, i.e., starting from 'const myAlert'.)//-------------------------------------------------------------------// JS// Closure example 4constnewClue=(name)=>{constlength=name.lengthreturn(weapon)=>{letclue=length+weapon.lengthreturn!!(clue%2)// note that '!!' here functions the same way as 'Boolean' would}}constdidGreenDoItWithA=newClue('Green')console.log(didGreenDoItWithA)// the function body that the 'newClue' function returns:/*
(weapon) => {
let clue = length + weapon.length
return !!(clue % 2) // note that '!!' here functions the same way as 'Boolean' would
}
*/console.log(didGreenDoItWithA('candlestick'))// falseconsole.log(didGreenDoItWithA('lead pipe'))// false// the point of including the above line is that its function call still 'remembers'// that 'Green' is the argument passed in to the 'newClue' function//-------------------------------------------------------------------// JS// Closure example 5constcountClues=()=>{letn=0return{// note this is returning an object with two functions in itcount:()=>++n,reset:()=>n=0}}letcounter=countClues()letcounter2=countClues()console.log(counter.count())// 1console.log(counter.count())// 2console.log(counter.count())// 3console.log(counter.reset())// 0console.log(counter2.count())// 1console.log(counter2.count())// 2console.log(counter2.count())// 3console.log(counter2.reset())// 0console.log(counter.count())// 1console.log(counter2.count())// 1console.log(counter.count())// 2//-------------------------------------------------------------------// JS// Closure example (Gandolfo's "Closure Recipe")letscope='global scope'functioncheckScope(){letinnerVar='local scope'functioninnerFunc(){returninnerVar}returninnerFunc}lettest=checkScope()console.log(test)// the body of the 'innerFunc' function is loggedconsole.log(test())// local scope//-------------------------------------------------------------------// JS// This example shows why it's really important to understand// the order in which functions executeconstfindSomeone=()=>{constspeak=()=>{console.log(who)// Why hello there, Prof Plum!}letwho='Why hello there, Prof Plum!'returnspeak}constsomeoneSpeak=findSomeone()console.log(someoneSpeak())// undefined//-------------------------------------------------------------------// JS// This closure example really shows why it's important to understand the order in which the code executes.// Based on Robert's response to my questions:// The *order* in which the lines of code run is annotated.constmakeTimer=()=>{letelapsed=0// *2*conststopwatch=()=>{returnelapsed}// *3* // Creates a function local to the 'makeTimer' function.constincrease=()=>elapsed++// *4* // Creates a function local to the 'makeTimer' function.setInterval(increase,1000)// *5* // Calls 'setInterval', to which the 'increase' function is passed, and 'increase' is not yet run but is *queued to run* (more on this below).returnstopwatch// *6*}lettimer=makeTimer()// *1* (But note that this 'makeTimer' function call is not actually stored in 'timer' until 'makeTimer' has run, and that what exactly gets stored at that point is simply what 'makeTimer' returns, which is the 'stopwatch' function body.)// *7*: With every call of 'timer' in the console (which is effectively calling the 'stopwatch' function and therefore returning 'elapsed'), logged is the number of seconds since 'makeTimer' was called and hence 'elapsed' was initialized (and 'makeTimer' being called is also what *queues up to run* 'increase', which increments 'elapsed'). Why "queues up"? Because 'elapsed' is actually returned (as a result of the calling of 'timer') BEFORE the incrementing of 'elapsed' ever reaches the one second mark, but AFTER the incrementing of 'elapsed' is queued (which, again, occurs during the calling of 'makeTimer').// (Note that there's nothing in this code that will ever stop the incrementing and that in reality this would have to be remedied.)// Closure as it relates to this example: Even though the call stack is cleared after the 'makeTimer' function runs, any variable still needed for reference is "remembered". In this case, 'stopwatch' retains a link to what's needed, e.g., anything affecting 'elapsed'. //-------------------------------------------------------------------// JS// CREATING a 'curry' functionconstcurry=(fn)=>{return(arg)=>{return(arg2)=>{returnfn(arg,arg2)}}}// USING the 'curry' function created aboveconstfunc=function(a,b){return[a,b]}constcurried=curry(func)console.log(curried(1)(2))// [1, 2]//-------------------------------------------------------------------// JS// CREATING a 'compose' functionconstcompose=(fn,fn2)=>{return(arg)=>{constresult=fn2(arg)returnfn(result)}}// USING the 'compose' function created aboveconstconsider=(name)=>{return`I think it could be...${name}`}constexclaim=(statement)=>{return`${statement.toUpperCase()}!`}constblame=compose(consider,exclaim)console.log(blame('you'))// I think it could be...YOU!
Top comments (0)
Subscribe
For further actions, you may consider blocking this person and/or reporting abuse
Top comments (0)