Skip to content

Instantly share code, notes, and snippets.

@tgrecojs
Created May 20, 2018 09:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tgrecojs/8122ea7526fa246c241868869b944eb6 to your computer and use it in GitHub Desktop.
Save tgrecojs/8122ea7526fa246c241868869b944eb6 to your computer and use it in GitHub Desktop.

Mostly Adequete FP Notes

Chapter 9

var Container = function(x) {
  this.__value = x;
}

Container.of = function(x) { return new Container(x); };
  • Container is an object with one property. Lots of containers just hold one thing, though they aren't limited to one. We've arbitrarily named its property __value.
  • The __value cannot be one specific type or our Container would hardly live up to the name.
  • Once data goes into the Container it stays there. We could get it out by using .__value, but that would defeat the purpose.
// (a -> b) -> Container a -> Container b
Container.prototype.map = function(f) {
  return Container.of(f(this.__value));
}

Why is this helpful

  • We can work with __value from inside of the container.
  • Secure our value & can work with different data types && handle null....

Container is basic --> Enter "Maybe" (Both functors - "mapable")

  • Container
    • is fairly boring.
    • has about the same impact as our id function(again there is a mathematical connection we'll look at when the time is right). However, there are other functors that have a proper map function which can provide useful behaviour whilst mapping.

Maybe Functor

  • Maybe functors enforce null checks.
  • don't have to write if(null === undefined) every where --> define it once and let it do it's thing.
  • Enforcing null check with Maybe:
    • Use a function like safeHead which checks for the existence of array and supplies our function with that intel
    • Intentionally cause null

Explicitly supply null example

//  withdraw :: Number -> Account -> `Maybe`(Account)
var withdraw = curry(function(amount, account) {
  return account.balance >= amount ?
    `Maybe`.of({
      balance: account.balance - amount,
    }) :
    `Maybe`.of(null);
});

//  finishTransaction :: Account -> String
var finishTransaction = compose(remainingBalance, updateLedger); // <- these composed functions are hypothetical, not implemented here...

//  getTwenty :: Account -> `Maybe`(String)
var getTwenty = compose(map(finishTransaction), withdraw(20));


getTwenty({
  balance: 200.00,
});
// `Maybe`("Your balance is $180.00")

getTwenty({
  balance: 10.00,
});
// `Maybe`(null)
//  safeHead :: [a] -> `Maybe`(a)
var safeHead = function(xs) {
  return `Maybe`.of(xs[0]);
};

var streetName = compose(map(_.prop('street')), safeHead, _.prop('addresses'));

streetName({
  addresses: [],
});
// `Maybe`(null)

streetName({
  addresses: [{
    street: 'Shady Ln.',
    number: 4201,
  }],
});
// `Maybe`("Shady Ln.")

Maybe Notes Continued

  • Writing unsafe software is like taking care to paint each egg with pastels before hurling it into traffic; like building a retirement home with materials warned against by three little pig.
  • Characteristics of a true null checking monday
    • split in 2 types:
      • 1 - checks for a something (value
      • 1 - checkss for nothing
    • Some(x) / None or Just(x) / Nothing are often used instead of a Maybe
  • Either *throw ... catch is not pure * when an error is thrown, it throws a fit of 0s and 1s against the input.
    • Instead of blowing a binary load, we can use Either
  • Functors are great for lots of reasons. Most importantly, they’re an abstraction that you can use to implement lots of useful things in a way that works with any data type.
  • For instance, what if you want to kick off a chain of operations, but only if the value inside the functor is not undefined or null?
  • Monads are a way to compose functions that require context in addition to the return value.

    • I/O, branching, computation
  • Moads type lift, flatten, and map so that types line up for lifting functions a => M(b)

  • "A mapping from some type a to some type b along with some computational context (hidden within the implementaton of lift map and flatten)

  • Functions Map, Functors map with context, Monads flatten AND map with context.

    • map- apply a fn to a and return b (a => b)
    • context - computation detail of monad's composition (lift,flatten, map).
      • allows us to compose monads
      • Mapping inside the context means that you apply a function from a => b to the value inside the context, and return a new value b wrapped inside the same kind of context
    • typelift - lift a type into a context so we can compute with that value.
    • flatten - unwrap the value F(a) => a
  • A monad is a type of functor

  • if you want to compose functions from a => F(b), b => F(c), and so on, you need monads. Let's swap the F() for M() to make that clear:

  • For synchronous, eager function applications over array data, this is overkill. However, lots of things are asynchronous or lazy, and lots of functions need to handle messy things like branching for exceptions or empty values.

Performance Warning: I’m not recommending this for arrays. Composing functions in this way would require multiple iterations over the entire array (which could contain hundreds of thousands of items). For maps over an array, compose simple a -> b functions first, then map over the array once, or optimize iterations with .reduce() or a transducer.

Promise Vs. Functors

  • .then() behaves differently & does not strictly obey all the mathematical laws that all functors and/or monads must satisfy for all given values.
  • Promises expect a then.
    • They are different from Monads because they don't type lift. Instead, the expect a promise.
  • if then is called chain it wont call it right away, it will wait, then retrieve.
# Composing with functions
g:           a => b
f:                b => c
h = f(g(a)): a    =>   c

# Composing with functors
g:             F(a) => F(b)
f:                     F(b) => F(c)
h = f(g(Fa)):  F(a)    =>      F(c)

# Composing with Monads
g:                  a => M(b)
f:                       b => M(c)
h = composeM(f, g): a    =>   M(c)

Fuggin' sick compose method

const composeM = method => (...ms) => (
  ms.reduce((f, g) => x => g(x)[method](f))
);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment