Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

example for composition law in ch10 for Applicative Functors is not clear/wrong #587

Open
deleite opened this issue Nov 7, 2020 · 1 comment

Comments

@deleite
Copy link

deleite commented Nov 7, 2020

I might did not get it but I was trying to run the sample in the example for the composition law and the part below does not seem to work:

const u = IO.of(toUpperCase);
const v = IO.of(concat('& beyond'));
const w = IO.of('blood bath ');

const test = IO.of(compose).ap(u).ap(v).ap(w)
test.unsafePerformIO() gives 'x.toUpperCase is not a function'

can anyone help me understand what am I doing wrong or if the sample is incorrect.

@sevillaarvin
Copy link

I was confused as well. Based on my testing, the implementation of compose as defined in the appendix https://mostly-adequate.gitbook.io/mostly-adequate-guide/appendix_a#compose throws an error:

const compose = (...fns) => (...args) => fns.reduceRight((res, fn) => [fn.call(null, ...res)], args)[0];

If we change its implementation to accept just two functions then it works:

const compose = curry((f, g) => (x) => f(g(x)))

Also, append would make more sense here instead of concat.

#+begin_src js :noweb no-export
  <<js io applicative demo>>
  <<js curry>>
  <<js concat>>
  // <<js compose>>

  const compose = curry((f, g) => (x) => f(g(x)))

  const toUpperCase = (x) => x.toUpperCase()

  const u = IO.of(toUpperCase)
  const v = IO.of(concat('& beyond'))
  const w = IO.of('blood bath ')

  const left = IO.of(compose).ap(u).ap(v).ap(w)
  const right = u.ap(v.ap(w))

  return {
    left: left.unsafePerformIO(),
    right: right.unsafePerformIO()
  }
#+end_src

#+RESULTS:
: { left: '& BEYONDBLOOD BATH ', right: '& BEYONDBLOOD BATH ' }
I leave the full implementation below:
class IO {
  constructor(fn) {
    this.unsafePerformIO = fn;
  }

  // [util.inspect.custom]() {
  //   return 'IO(?)';
  // }

  // ----- Pointed IO
  static of(x) {
    return new IO(() => x);
  }

  // ----- Functor IO
  map(fn) {
    return new IO(compose(fn, this.unsafePerformIO));
  }

  // ----- Applicative IO
  ap(f) {
    return this.chain(fn => f.map(fn));
  }

  // ----- Monad IO
  chain(fn) {
    return this.map(fn).join();
  }

  join() {
    return new IO(() => this.unsafePerformIO().unsafePerformIO());
  }
}
const curry = (f) => {
  const arity = f.length

  return function currier(...args) {
    if (args.length < arity) {
      return currier.bind(null, ...args)
    }

    return f.apply(null, args)
  }
}
const concat = curry((a, b) => a.concat(b))
// const compose = (...fs) => (...args) => {
//   return fs.reduceRight(
//     (result, f) => [f.apply(null, result)],
//     args
//   )[0]
//   // alternatively:
//   // return fs.reduceRight((result, f) => f.apply(null, [].concat(result)), args)
// }

const compose = curry((f, g) => (x) => f(g(x)))

const toUpperCase = (x) => x.toUpperCase()

const u = IO.of(toUpperCase)
const v = IO.of(concat('& beyond'))
const w = IO.of('blood bath ')

const left = IO.of(compose).ap(u).ap(v).ap(w)
const right = u.ap(v.ap(w))

return {
  left: left.unsafePerformIO(),
  right: right.unsafePerformIO()
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants