Code Monkey home page Code Monkey logo

functional-light-js-chapters-3-and-4's Introduction

Chapter 3

Previously on Functional-Lite JS: Functions

This week: Managing Inputs (Arguments/Parameters)

“Arguments are the values you pass in, and parameters are the named variables inside the function that receive those passed-in values.”

##Many arguments into one

unary()

Utility that takes a function, utility will pass multiple arguments, however function takes only single arguments

Create helper function that enforces the unary-ness (taking only one argument)

##One argument, return argument

identify()

Returns argument passed in.

Useful as function argument for things like filter(). JS will coerce value into boolean.

identity() also used as default function argument to transform functions.

##No argument, return value

constant()

Return a constant value as a function.

Useful in then() in JS Promises. Requires function even if only returning value.

Many use arrow function, but consider not doing that.

##From Arguments to Params

spreadArgs()

Arrays are handy to pass in as arguments, especially using deconstruction ...args.

What do you do when you can't change functions' arguments? Utilities, libraries, etc.

spreadArgs() allows to return multiple values in array, but use those values independantly to pass to other functions

gatherArgs(): Opposite of spreadArgs()

##Arguments not passed in at same time

partial()

Situation: API calls where urls are known, but data and callback for response come later.

Option: Write wrappers that call ajax with url set.

Can be good but gets out of hand with setting arguments as well:

Get in the habit of looking for patterns where same things are done repeatedly. Good opportunity for reusable utilties.

##Argument Application

Apply or appliation When function is called, arguments are 'applied' to parameters.

Partial Application getOrder(data, cb) is a 'partial application' of ajax(url, data, cb) as it applies a single argument into a parameter, but other arguments are left for later.

Partial application is a reduction of a function's arity.

Arity “Arity is the number of parameters in a function declaration”

partial() takes in initial arguments, then returns a function that will take more arguments, then calls the intial function with both sets of arguments.

Why does this work? Closures!

partiallyApplied() 'closes' over fn and presetArgs.

##bind(): The JS built-in partial(). No, it's bad

bind() does two things

  • presets this context
  • partially applys arguments

Kyle's take: Misguided to have combine these two responsbilities. Sometimes you'll want one and not the other. Never needed both at same time.

###Reversing arguments

reverseArgs()

ajax signature is ajax( url, data, cb).

Want to apply the callback cb, but have other args later? Using a reverse function, we can partially apply from the right, as opposed to the left.

##One at a time

Currying: a technique similiar to partial application, where multiple arguments are broken down into chained functions that are arity 1

curriedAjax() receives one argument at a time, each in a seperate call.

Currying partially applies another argument to the original function, until all arguments have been passed. Each step returns a function that only accepts the next argument.

Nesting dolls of functions.

So currying unwinds a single higher-arity function into a series of chained unary functions.

Example of currying with add function:

[1,2,3,4,5].map( curry( add )( 3 ) );
// [4,5,6,7,8]

Why choose curry(add)(3) vs partial(add, 3)?

When you know you want to use add, but don't know the value to be added.

Currying creates a more specialized function with each return that can be captured and reused, while partial needs to be recalled each time.

Both use closure.

Visualization of curried functions call chain:

function curriedSum(v1) {
    return function(v2){
        return function(v3){
            return function(v4){
                return function(v5){
                    return sum( v1, v2, v3, v4, v5 );
                };
            };
        };
    };
}

// ES6 arrow functions
curriedSum =
    v1 =>
        v2 =>
            v3 =>
                v4 =>
                    v5 =>
                        sum( v1, v2, v3, v4, v5 );

curriedSum = v1 => v2 => v3 => v4 => v5 => sum( v1, v2, v3, v4, v5 );

##Why would you use currying/partial application?

They both separate when and where arguments are specified, in both time and space.

Currying also allows composition of functions.

We can pass what arguments we know into a function, then later, in a different callsite, we can complete the argument list and get the final data back.

This also enforces semantic boundary: separating how we get data and what we do with data later.

Haskell has automatic currying: foo 1 2 3 vs foo(1)(2)(3) in JS.

Some JS FP libraries can curry multiple arguments at once

Currying can also be undone with an uncurry(), though may not be the same as the original function that was curried.

##Order matters

We're juggling argument order, but this is all because of positional dependence of arguments. This creates a lot of mess in the code.

##Spreading Properties

In spreadArgs(), it depends of argument order to pull values.

With named arguments, there is guarantee of order when calling.

JS functions have .toString() that gives string representation, including argument signature.

Trade-offs: argument order vs named argument. 'first argument' vs 'argument named x'.

##Point-free style

Popular style in FP world is tacit programming (point-free). Point refers to the parameter not needing to set a return value to variable to pass it into another function.

Helper utilities like not() or when() to reduce points in a refactor.

Point-free is cool, but use your judgement. It can be a lot of jumping through hoops to improve readability and may degrade readability if taken too far.

##Questions

  1. Are there places within Ironboard that could benefit from currying or partial application?

#Chapter 4 - Composing Functions

Functional programming: seeing every function like a Lego piece. Small on its own, but useful to put together with others.

However, sometimes, one function/piece fits with another function/piece so often that they are more used together than apart. That is a new function that is easier to think about together.

##Output to Input

To compose: pass output of first function as input to second function.

arrayValue <-- map <-- unary <-- parseInt //right-to-left is common in FP and makes sense later.

parseInt() is input to unary(). unary() output is input to map(). map() output is arrayValue. Composition of map and unary

Example workflow: wordsUsed <-- unique <-- words <-- text

##A composition-making machine

If compositions are good, is there a way to create these compositions without needing to rewrite functions to accept output?

Keep parameter order in mind, fn2 before fn1. The functions compose right-to-left, so argument order is listed in that order. Very common for FP libraries to define compose() right-to-left.

Execution order is right-to-left, but code order is left-to-right.

var uniqueWords = compose2( unique, words );

##Composition Variation

Functions can be composed the other way as well. Sometimes, it works, but we wary.

##General Composition

With composition, you could combine any number of functions.

Most powerful tricks of Function Programming!

  • A combination of partial application and function composing allows some arguments to be set while still creating specialized variations. Could also curry but may need to reverse args.

##Alternative Implementations

Better to use the FP libraries versions of utilties especially compose, however understand how it works. There may be performance implications.

Potential implementations: reduce

  • 'fancy loop', reduces array to a single value
  • reduce([1,2,3,4,5]) // ((((1+2)+3)+4)+5) = 15
  • we can reduce a list of functions to make compose
  • each result step is passed as input to next call

Eager vs lazy implentation can have very different performance.

In initial version of compose, [...fns].reverse().reduce(...) calls reduce on every function, while fns.reverse().reduce(...) calls reduce once and defers calculation until the end.

Recursion offers another way. Recursion vs repetitive action with running result. YMMV.

##Reordered composition

Right-to-left is standard compose order.

  • pros
    • same order they appear in if composing manually
  • cons
    • functions are in reverse order of Execution
    • using partial application like partialRight to set first function is difficult

Left-to-right is called pipe.

From Unix where programs are strung together using the pipe (|) operator. Output is passed to next program.

  • pros
    • functions are listed in execution order
    • partial application is clearer
  • cons
    • ?

Pipe is the reverse arguments of compose

var pipe = reverseArgs( compose );

##Abstration

Pull out generality between two or more tasks

DRY code helps keep behavior common across tasks. Also keeps from needing to update logic in multiple places.

Abstration can be taken too far.

"Composition is helpful even if there's only once occurence of something"

Separation Enables Focus

"… abstraction is a process by which the programmer associates a name with a potentially complicated program fragment, which can then be thought of in terms of its purpose of function, rather than in terms of how that function is achieved. By hiding irrelevant details, abstraction reduces conceptual complexity, making it possible for the programmer to focus on a manageable subset of the program text at any particular time." -Michael L. Scott, Programming Language Pragmatics

Separate two pieces of functionality so you can focus on each piece independently of the other. Not black boxes that we never look into. Is about focus.

"We’re not abstracting to hide details; we’re separating details to improve focus."

Through focus via FP, code can be more readable and understandable.

Abstration creates a 'semantic boundary' between two pieces of functionality. Example, name of function. Separating the how from what.

Imperative vs declaritive code

Imperative: how to accomplish a tasks Declaritive: what the outcome should be

ES6 example of syntax that pushes declarative code: destructuring.

Destructuring describes how a compound value, like object or array, is taken apart.

Discussion Topics:

  • https://github.com/lodash/lodash/wiki/FP-Guide#mapping
  • How are people feeling about the longer functions vs ES6 versions? One easier to read?
  • Always use FP utilities? How do you remember, find those?
  • Helpful to see the 'returned function' version of functions like partial() implementation. Useful in normal development?
  • Benefits of currying? When would you create your own?
  • Trade-offs: argument order vs named argument. 'first argument' vs 'argument named x'. Both require knowledge about the function.
  • Kyle's style of naming could be anonymous functions...
function compose2(fn2,fn1) {
    return function composed(origValue){
        return fn2( fn1( origValue ) );
    };
}

find myself ignore what composed is called. Does naming everything help? Naming shows importance/usefulness so sometimes seems distracting?

  • In 'Machine Making', what level of utilities should we be making? Is 2 an optimal number for function composition?
  • In 'Composition Variation', it's pointed out that composing functions can sometimes be switched for a different purpose. Is this a valuable learning? Just a novel idea?
var uniqueWords = compose2( unique, words );
//versus
var letters = compose2( words, unique );
  • In Alternate Composition, eager vs lazy vs recursion was discussed. Good ways to figure out performance characteristcs? Benchmark? Use returned function version?
  • Talking about pipes, doesn't really list a negative. Is there an instance where pipe is not good to use?
  • How much do agree with this 'overly-DRY' code:
function conditionallyStoreData(store,location,value,checkFn) {
    if (checkFn( value, store, location )) {
        store[location] = value;
    }
}

function notEmpty(val) { return val != ""; }

function isUndefined(val) { return val === undefined; }

function isPropUndefined(val,obj,prop) {
    return isUndefined( obj[prop] );
}

function saveComment(txt) {
    conditionallyStoreData( comments, comments.length, txt, notEmpty );
}

function trackEvent(evt) {
    conditionallyStoreData( events, evt.name, evt, isPropUndefined );
}
  • Composition is valuable if there is only one occurence vs DRY. Agree?

View Functional Light Js Chapters 3 And 4 on Learn.co and start learning to code for free.

functional-light-js-chapters-3-and-4's People

Contributors

malorie16 avatar matlc avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Forkers

malorie16

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.