-
Notifications
You must be signed in to change notification settings - Fork 1.9k
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
Chapter 10, Part Laws. We don't need liftA2(concat). #628
Comments
EDIT2: Nvm, just saw this #252, and realized that I needed to use the "pumped up" version of // NOTE A slightly pumped up version of `curry` which also keeps track of
// whether a function was called partially or with all its arguments at once.
// This is useful to provide insights during validation of exercises.
function curry(fn) {
assert(
typeof fn === 'function',
typeMismatch('function -> ?', [getType(fn), '?'].join(' -> '), 'curry'),
);
const arity = fn.length;
return namedAs(fn.name, function $curry(...args) {
$curry.partially = this && this.partially;
if (args.length < arity) {
return namedAs(fn.name, $curry.bind({ partially: true }, ...args));
}
return fn.call(this || { partially: false }, ...args);
});
} EDIT: So I finally got it working in javascript, but As we can see below, I had to #+begin_src js :noweb no-export :results code
<<js maybe applicative>>
<<js task applicative>>
<<js compose>>
<<js liftA2>>
<<js identity>>
<<js concat>>
const tOfM = compose(Task.of, Maybe.of)
const x = tOfM("Hello ")
const y = tOfM("World")
const curriedAndLiftedConcat = curry(liftA2(concat))
const z = liftA2(curriedAndLiftedConcat, x, y)
////// ERROR //////
// NOTE this curry-less function throws an error, why???
const onlyLiftedConcat = liftA2(concat)
const a = liftA2(onlyLiftedConcat, x, y)
let afork
try {
afork = a.fork(id, id)
} catch (error) {
afork = error.message
}
////// ERROR //////
return {
// x,
// xfork: x.fork(id, id),
// y,
// yfork: y.fork(id, id),
z,
zfork: z.fork(id, id),
a,
afork
}
#+end_src
#+RESULTS:
#+begin_src js
{
z: Task { fork: [Function (anonymous)] },
zfork: Maybe { val: 'Hello World' },
a: Task { fork: [Function (anonymous)] },
afork: "Cannot read properties of undefined (reading 'map')"
}
#+end_src Dependencies implementations: Maybe#+name: js maybe applicative
#+begin_src js
class Maybe {
constructor(val) {
this.val = val
}
static of(val) {
return new Maybe(val)
}
get isNothing() {
return this.val === null || this.val === undefined
}
map(fn) {
return this.isNothing ? this : new Maybe(fn(this.val))
}
join() {
return this.isNothing ? this : this.val
}
chain(fn) {
return this.map(fn).join()
}
ap(f) {
return f.map(this.val)
}
}
#+end_src Task#+name: js task applicative
#+begin_src js :noweb no-export
class Task {
constructor(fn) {
this.fork = fn
}
static of(val) {
return new Task((_reject, result) => result(val))
}
map(fn) {
<<js compose>>
return new Task(
(reject, result) => this.fork(
reject,
compose(result, fn)
)
)
}
join() {
return new Task((reject, result) => this.fork(
reject,
x => x.fork(reject, result)
))
}
chain(fn) {
return this.map(fn).join()
}
ap(f) {
return new Task((reject, resolve) => this.fork(
reject,
x => f.map(x).fork(reject, resolve)
));
}
}
#+end_src compose()#+name: js compose
#+name: js compose functional
#+begin_src js
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)
}
#+end_src liftA2()#+name: js liftA2
#+begin_src js :noweb no-export
<<js curry>>
const liftA2 = curry((g, f1, f2) => f1.map(g).ap(f2))
#+end_src curry()#+name: js curry
#+begin_src js
const curry = (f) => {
const arity = f.length
return (...args) => {
if (args.length < arity) {
return f.bind(null, ...args)
}
return f.apply(null, args)
}
}
#+end_src id()#+name: js identity
#+begin_src js
const id = (x) => x
#+end_src concat()#+name: js concat
#+begin_src js
const concat = curry((a, b) => a.concat(b))
#+end_src === ORIGINAL QUESTION ===Also I'd like to ask, what's the signature of When I try to analyze it, and assume that then by definition, Is it correct to assume that in this example |
This is a very old issue, but I also was a little confused about this, did some research and played around with the code for a while until I understood. I hope this helps someone reading in the future. The inner The signature of
So what you're proposing when you suggested liftA2(concat, tOfM('Rainy Days and Mondays'), tOfM(' always get me down')) would boil down to tOfM('Rainy Days and Mondays').map(concat).ap(tOfM(' always get me down')) And since However, if you do, as the author writes, liftA2(liftA2(concat), tOfM('Rainy Days and Mondays'), tOfM(' always get me down')) then this will become tOfM('Rainy Days and Mondays').map(liftA2(concat)).ap(tOfM(' always get me down')) which is perfect, since the call to Task.of(
liftA2(concat)(Maybe.of('Rainy days'))(Maybe.of('always down'))
) which is exactly what you want |
In chapter 10 on part laws. there is a code that demonstrates "applicatives are close under composition".
I think we could remove liftA2 wrapper for
concat
function, It's useless.liftA2(concat, tOfM('Rainy Days and Mondays'), tOfM(' always get me down'));
The text was updated successfully, but these errors were encountered: