Difficulty understanding functional programming composition, functors and monads example - javascript

I've kind of grasped some knowledge on functional programming but can't really wrap my head around this function programming block of code. I didn't really knew where I should ask something like this I couldn't figure out so asked it here. So I would really appreciate if someone will help me understand what this higher order function, or a monads example doing?
P.S this code is from composing software book by Eric Elliot
const f = n => n+1;
const g = n => n*2;
This composeM functions is made to compose and map or over numbers of functions? I know reduce but really have no idea how this function should be working.
const composeM = (...mps) => mps.reduce((f, g) => x => g(x).map(f));
const h = composeM(f,g);
h(20)
Then, the function composeM was more generalized by doing:
const compose = methods => (...mps) => mps.reduce((f, g) => x => g(x)[method](f));
Then, I could create composedPromises or composedMaps like
const composePromises = compose("then")(f,g);
How is the g(x)[method](f) even working? it should be g(x).then(f).
Update above map composeM function not working
const f = n => Promise.resolve( n+1 );
const g = n => Promise.resolve( n*2 );
const composePromises = (...mps) => mps.reduce((f, g) => x => g(x).then(f))
const h = composePromises(f, g)
h(20)

Consider function composition, which has the following type signature.
// compose :: (b -> c) -- The 1st argument is a function from b to c.
// -> (a -> b) -- The 2nd argument is a function from a to b.
// -> (a -> c) -- The final result is a function from a to c.
// +-----------------b -> c
// | +---------a -> b
// | | +-- a
// | | |
const compose = (f, g) => x => f(g(x));
// |_____|
// |
// c
The composeP function is similar to the compose function, except it composes functions that return promises.
// composeP :: (b -> Promise c) -- The 1st argument is a function from b to promise of c.
// -> (a -> Promise b) -- The 2nd argument is a function from a to promise of b.
// -> (a -> Promise c) -- The final result is a function from a to promise of c.
// +-------------------------b -> Promise c
// | +-------- a -> Promise b
// | | +-- a
// | | |
const composeP = (f, g) => x => g(x).then(f);
// |__________|
// |
// Promise c
Remember that the then method applies the callback function to the value of the promise. If we replace .then with [method] where method is the name of the bind function of a specific monad, then we can compose functions that produces values of that monad.
For example, .flatMap is the bind function of arrays. Hence, we can compose functions that return arrays as follows.
// composeA :: (b -> Array c) -- The 1st argument is a function from b to array of c.
// -> (a -> Array b) -- The 2nd argument is a function from a to array of b.
// -> (a -> Array c) -- The final result is a function from a to array of c.
const composeA = (f, g) => x => g(x).flatMap(f);
// f :: Bool -> Array String
const f = x => x ? ["yes"] : ["no"];
// g :: Int -> Array String
const g = n => [n <= 0, n >= 0];
// h :: Int -> Array String
const h = composeA(f, g);
console.log(h(-1)); // ["yes", "no"]
console.log(h(0)); // ["yes", "yes"]
console.log(h(1)); // ["no", "yes"]
That was a very contrived example but it got the point across.
Anyway, the generic compose function composes monads.
const compose = method => (f, g) => x => g(x)[method](f);
const composeP = compose("then");
const composeA = compose("flatMap");
Finally, the various monad compose functions only compose two functions at a time. We can use reduce to compose several of them at once. Hope that helps.

Related

How to implement Haskell's newtype using a function encoding?

Heads-up: This is a cross-language question.
I will demonstrate the problem by means of implementing a difference list. Here is the Scott encoded List, which provides the basic type. I use it with a dynamic type validator, hence I need a wrapper to associate the type List a with (simplified in the example below):
// (forall r. r -> (a -> List a -> r) -> r) -> List a
const List = k =>
({[Symbol.toStringTag]: "List", run: k}); // type wrapper + namespace
// a -> List a -> List a
List.Cons = x => xs =>
List(nil => cons => cons(x) (xs));
// List a
List.Nil = List(nil => cons => nil);
// List a -> List a -> List a
List.append = xs => ys => function go(acc) {
return acc.run(ys)
(x => xs_ =>
List.Cons(x) (thunk(() => go(xs_)))); // A
} (xs);
// List a
List.empty = List.Nil;
The expression thunk(() => ...) in line A creates an implicit thunk, i.e. (except for ===) you can treat it as the expression the thunk is deferring. In this case it has type Last a.
This is pretty much standard in a eager language without ADT. Next I want to offer efficient append and snoc operations supplied by a difference list. At this point things are getting messy. In Haskell such a type is declared with a newtype wrapper, but I don't know how to implement it using Scott encoding. So I stick with the normal encoding:
// (forall r. ((List a -> List a) -> r) -> r) -> DList a
const DList = k =>
({[Symbol.toStringTag]: "DList", run: k}); // type wrapper + namespace
// (List a -> List a) -> DList a
DList.Cons = fun(
f => DList(cons => cons(f));
// DList<a> => DList<a> => DList<a>
DList.append = f => g => DList.Cons(
xs => f.run(
cons => cons(g.run( // B
cons_ => cons_(xs))))); // B
// DList a
DList.empty = DList.Cons(
xs => List.append(List.Nil) (xs));
Well, this works but the implementation of such an easy thing as the monoid instance is rather entangled. Having to pattern match (cons(...) and cons_(...) in line B) to get the partially applied List.append (List a -> List a) is redundant. and unsecessarily complicating.
Maybe it is as simple as dropping the Scott encoding altogether, but I don't want to lose the type abstraction from List a -> List a to DList a on the type level. Hopefully someone with more experience can point the right way.
Answers both using Haskell or JS are appreciated.
We can simplify the implementation of DList.append and DList.empty as follows.
const comp = f => g => x => f(g(x));
const id = x => x;
DList.append = xs => ys =>
xs.run(f =>
ys.run(g =>
DList.Cons(comp(f)(g))));
DList.empty = DList.Cons(id);
However, it would be even simpler if we didn't use CPS at all.
// (List a -> List a) -> DList a
const DList = run => ({ [Symbol.toStringTag]: "DList", run });
DList.append = xs => ys => DList(comp(xs.run)(ys.run));
DList.empty = DList(id);

How to use lift if both function and arguments are “wrapped”

I’ve been trying to implement an Apply/Applicative type based on Javascript Functor, Applicative, Monads in pictures and the blog series Fantas, Eel, and Specification.
I think I’m making good progress, but I ran in to a case I couldn’t really find in any of the articles.
TL;DR Question
If lift2 is
f -> A.of(x) -> A.of(y) -> A.of(f (x) (y)) -or- A(y).ap(A(x).map(f))
what is the theory/name/type behind
A.of(f) -> A.of(x) -> A.of(y) -> A(f (x) (y)) -or- A(y).ap(A(x).ap(A(f)))
Introduction
I’m working with knockout.js, which gives me observable values. I’m trying to use them in a kind of functional fashion, extending them when needed.
First, I implemented map to make myself a functor:
ko.subscribable.fn.map = function(f) {
// note: calling without arguments is knockout's
// way of "unwrapping"
return ko.pureComputed(
() => f(this())
);
}
This allows me to do things like:
// "Pure" part describing my app
const myValue = ko.observable(2);
const doubleThat = myValue.map(x => x * 2);
// In- and output (IO?)
doubleThat.subscribe(console.log);
myValue(3); // Logs 6
Then, I ran in to the problem of working with functions that take multiple arguments. For example:
const filter = (pred, xs) => xs.filter(pred);
I solved my issues by implementing ap and currying my functions:
ko.subscribable.fn.ap = function(sf) {
return ko.pureComputed(
() => sf () (this())
);
};
const filter = pred => xs => xs.filter(pred);
With these changes in place, I can do:
const odd = x => x % 2 === 1;
const myPred = ko.observable(odd);
const myValues = ko.observable([ 1, 2, 3 ]);
const myFilter = myPred.map(filter);
const myResult = myValues.ap(filter); // S([ 1, 3 ])
The definition of lift2 gives me another way of writing the same thing.
const myResult = lift2 (filter) (myPred) (myResult)
So far, so good. I can use the dot-calls if the interim result is reusable, and a liftN call if I only care about the final outcome.
The problem
The liftN way of chaining one map with N - 1 calls to ap only works if I use plain functions. In my app however, I often deal with functions that are themselves wrapped in subscribables! For example:
const sum = x => y => x + y;
const mathStrategy = ko.observable(sum);
const v1 = ko.observable(2);
const v2 = ko.observable(3);
My attempts
Chaining works, but quickly gets very hard to understand.
// Ugly...
const myResult = v2.ap(v1.ap(mathStrategy)); // S(5)
I can use liftN, but only if I make sure my first function is id.
// Also ugly...
const id = x => x;
const myResultL = lift3 (id) (mathStrategy) (v1) (v2); // S(5)
My questions
If lift2 handles f -> A.of(x) -> A.of(y) -> A.of(f (x) (y)), what is the theory/name/type behind A.of(f) -> A.of(x) -> A.of(y) -> A(f (x) (y))
If such a thing does not really “exist”, would it be okay to write an implementation of ap that unwraps A(f) on the go? (i.e. f => ko.unwrap (f) (x))
Code example
Object.assign(ko.subscribable, {
of: function(x) {
return ko.pureComputed(() => x)
}
});
Object.assign(ko.subscribable.fn, {
map: function(f) {
return ko.pureComputed(() => f(this()));
},
ap: function(sf) {
return ko.pureComputed(() => sf () (this()));
},
toString: function() {
return `S(${JSON.stringify(this())})`;
}
});
// Example code:
const sum = x => y => x + y;
const mult = x => y => x * y;
const mathStrategy = ko.observable(sum);
const v1 = ko.observable(1);
const v2 = ko.observable(3);
const result = v2.ap(v1.ap(mathStrategy));
console.log(result); // S(4)
v1(2);
mathStrategy(mult);
console.log(result); // S(6)
.as-console-wrapper { min-height: 100% !important; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
Note: This is kind of related to a question I asked earlier. Back then, I was focusing on lazily unwrapping A(x) and A(y), which I have given up on by now 😉.
I think the question you meant to ask, with proper notation for the types, is
If lift2 handles Apply f => (x -> y -> z) -> f x -> f y -> f z, what is the theory/name behind Apply f => f (x -> y -> z) -> f x -> f y -> f z?
Such a function is rare, because everyone just uses ap or the respective infix operator, like in Haskell
let az = af <*> ax <*> ay
However, I saw some two references on the internet to it being called ap2 [1][2], which makes sense as it is analogous to lift becoming lift2.
You can write this helper function as
const ap2 = af => ax => ay => ap(ap(af, ax), ay)
or like you already did
const ap2 = lift3(id)

Pointfree composed function with spreaded arguments

I'm trying to figure out if there is a pattern for writing pointfree composed function when the arguments should be spreaded in curried composing functions
i.e (with Ramda):
add_1_and_multiply = (add, mul) => R.compose(R.multiply(mul), R.add(1))(add)
add_1_and_multiply(3, 5) // 20
How to write add_1_and_multiply in pointfree style?
I'm not sure if you can easily combine pointfree style and non-unary arity.
Think first what should be the type of the resulting and composed functions:
// Compose: (B -> C) -> (A -> B) -> A -> C
const compose = f => g => x => f(g(x))
// Add: A -> A -> A
const add = x => y => x + y
// Mul: A -> A -> A
const mul = x => y => x * y
// Add1: A -> A
const add1 = add(1)
// Add1AndMul: A -> A -> A
// because:
// Add1: A -> A
// Mul: A -> A -> A
const add_1_and_mul = compose(mul)(add1)
// Mul4: A -> A
const mul_4 = add_1_and_mul(3)
const result = mul_4(5) //> 20
Ramda has uncurryN so you can wrap it around the compose and get rid of the currying of the resulting function.
const add_1_and_multiply = R.uncurryN(2, R.compose(R.multiply, R.add(1)))
let result2 = add_1_and_multiply(3, 5) //> 20
To add another function to the "chain" you need to compose it with previous function.
// Add1AndMul: A -> A -> A
const add1_mul = compose(mul)(add1)
This is our desired signature.
// 1 2 3
// Add1AndMulAndAdd: A -> A -> A -> A
// which is: | | |
// Add1: A -> A | |
// Mul: A -> A -> A |
// Add: A -> A -> A
So somehow we have to pass those A2 and A3 without any "points".
Let's try just simple composition and analyze it:
let add1_mul_add = compose(add)(add1_mul)
Remeber signature of compose: (E -> F) -> (D -> E) -> D -> F!
Analyzing it in steps:
We supply our add function signature instead of (E -> F)
(E -> F )
(A -> A -> A)
We conclude that
E = A
F = A -> A
We do the same to (D -> E) and add1_mul
(D -> E )
(A -> A -> A)
We conclude that
D = A
E = A -> A
But we can already see a contradiction there!
Conclusion in step 2 contradicts conclusion in step 1:
E cannot be A and A -> A at the same time.
Therefore we cannot compose add and add1_mul and our add1_mul_add will throw an error.
Let's try to workaround the problem and fix it breaking our promise of pointfree style.
const add1_mul_add = x => compose(add)(add1_mul(x))
I'm going to break some rules and mix signatures with code to illustrate my point:
x -> (A -> A -> A) -> (x -> A -> A) -> A -> A -> A
||
\/
x -> (A -> A -> A) -> (A -> A) -> A -> A -> A
(E -> F ) -> (D -> E) -> D -> F
So we got our correct compose signature! How to get rid of the x variable to go back to pointfree?
We can try to look for obvious patterns, like for example... our ye olde function composition!
f(g(x)) => compose(f)(g)
And we find this pattern in our new add1_mul_add -
f = compose(add)
g = add1_mul
f(g(x)) = compose(add)(add1_mul(x))
And we reduce it to pointfree and we got our new add1_mul_add function:
const add1_mul_add = compose(compose(add))(add1_mul)
But hey - we can reduce it even more!
const add1_mul_add = compose(compose)(compose)(add)(add1_mul)
And there we have found something that already exists in haskell under the name of The Owl.
We can define it in Javascript simply as:
const owl = compose(compose)(compose)
But now, with every new function in the chain, you would have to create a higher order of the owl operator.
const owl2 = compose(compose)(owl)
const add1_mul_add_mul = owl2(mul)(add1_mul_add)
const owl3 = compose(compose)(owl2)
const add1_mul_add_mul_add = owl3(add)(add1_mul_add_mul)
So I really recommend having your functions unary in pointfree style. Or use other constructs like lists:
const actions = [ add, mul, add, mul ]
const values = [ 1, 2, 3, 4 ]
const add_mul_add_mul = (...values) => zip(actions, values).reduce((acc, [action, value]) => action(acc, value), 0)

Default parameter value undefined; is this a JavaScript Bug?

Below is a syntactically valid javascript program – only, it doesn't behave quite the way we're expecting. The title of the question should help your eyes zoom to The Problem Area
const recur = (...args) =>
({ type: recur, args })
const loop = f =>
{
let acc = f ()
while (acc.type === recur)
acc = f (...acc.args)
return acc
}
const repeat = n => f => x =>
loop ((n = n, f = f, x = x) => // The Problem Area
n === 0
? x
: recur (n - 1, f, f (x)))
console.time ('loop/recur')
console.log (repeat (1e6) (x => x + 1) (0))
console.timeEnd ('loop/recur')
// Error: Uncaught ReferenceError: n is not defined
If instead I use unique identifiers, the program works perfectly
const recur = (...args) =>
({ type: recur, args })
const loop = f =>
{
let acc = f ()
while (acc.type === recur)
acc = f (...acc.args)
return acc
}
const repeat = $n => $f => $x =>
loop ((n = $n, f = $f, x = $x) =>
n === 0
? x
: recur (n - 1, f, f (x)))
console.time ('loop/recur')
console.log (repeat (1e6) (x => x + 1) (0)) // 1000000
console.timeEnd ('loop/recur') // 24 ms
Only this doesn't make sense. Let's talk about the original code that doesn't use the $-prefixes now.
When the lambda for loop is being evaluated, n as received by repeat, is available in the lambda's environment. Setting the inner n to the outer n's value should effectively shadow the outer n. But instead, JavaScript sees this as some kind of problem and the inner n results in an assignment of undefined.
This seems like a bug to me but I suck at reading the spec so I'm unsure.
Is this a bug?
I guess you already figured out why your code doesn't work. Default arguments behave like recursive let bindings. Hence, when you write n = n you're assigning the newly declared (but yet undefined) variable n to itself. Personally, I think this makes perfect sense.
So, you mentioned Racket in your comments and remarked on how Racket allows programmers to choose between let and letrec. I like to compare these bindings to the Chomsky hierarchy. The let binding is akin to regular languages. It isn't very powerful but allows variable shadowing. The letrec binding is akin to recursively enumerable languages. It can do everything but doesn't allow variable shadowing.
Since letrec can do everything that let can do, you don't really need let at all. A prime example of this is Haskell which only has recursive let bindings (unfortunately called let instead of letrec). The question now arises as to whether languages like Haskell should also have let bindings. To answer this question, let's look at the following example:
-- Inserts value into slot1 or slot2
insert :: (Bool, Bool, Bool) -> (Bool, Bool, Bool)
insert (slot1, slot2, value) =
let (slot1', value') = (slot1 || value, slot1 && value)
(slot2', value'') = (slot2 || value', slot2 && value')
in (slot1', slot2', value'')
If let in Haskell wasn't recursive then we could write this code as:
-- Inserts value into slot1 or slot2
insert :: (Bool, Bool, Bool) -> (Bool, Bool, Bool)
insert (slot1, slot2, value) =
let (slot1, value) = (slot1 || value, slot1 && value)
(slot2, value) = (slot2 || value, slot2 && value)
in (slot1, slot2, value)
So why doesn't Haskell have non-recursive let bindings? Well, there's definitely some merit to using distinct names. As a compiler writer, I notice that this style of programming is similar to the single static assignment form in which every variable name is used exactly once. By using a variable name only once, the program becomes easier for a compiler to analyze.
I think this applies to humans as well. Using distinct names helps people reading your code to understand it. For a person writing the code it might be more desirable to reuse existing names. However, for a person reading the code using distinct names prevents any confusion that might arise due to everything looking the same. In fact, Douglas Crockford (oft-touted JavaScript guru) advocates context coloring to solve a similar problem.
Anyway, back to the question at hand. There are two possible ways that I can think of to solve your immediate problem. The first solution is to simply use different names, which is what you did. The second solution is to emulate non-recursive let expressions. Note that in Racket, let is just a macro which expands to a left-left-lambda expression. For example, consider the following code:
(let ([x 5])
(* x x))
This let expression would be macro expanded to the following left-left-lambda expression:
((lambda (x) (* x x)) 5)
In fact, we can do the same thing in Haskell using the reverse application operator (&):
import Data.Function ((&))
-- Inserts value into slot1 or slot2
insert :: (Bool, Bool, Bool) -> (Bool, Bool, Bool)
insert (slot1, slot2, value) =
(slot1 || value, slot1 && value) & \(slot1, value) ->
(slot2 || value, slot2 && value) & \(slot2, value) ->
(slot1, slot2, value)
In the same spirit, we can solve your problem by manually "macro expanding" the let expression:
const recur = (...args) => ({ type: recur, args });
const loop = (args, f) => {
let acc = f(...args);
while (acc.type === recur)
acc = f(...acc.args);
return acc;
};
const repeat = n => f => x =>
loop([n, f, x], (n, f, x) =>
n === 0 ? x : recur (n - 1, f, f(x)));
console.time('loop/recur');
console.log(repeat(1e6)(x => x + 1)(0)); // 1000000
console.timeEnd('loop/recur');
Here, instead of using default parameters for the initial loop state I'm passing them directly to loop instead. You can think of loop as the (&) operator in Haskell which also does recursion. In fact, this code can be directly transliterated into Haskell:
import Prelude hiding (repeat)
data Recur r a = Recur r | Return a
loop :: r -> (r -> Recur r a) -> a
loop r f = case f r of
Recur r -> loop r f
Return a -> a
repeat :: Int -> (a -> a) -> a -> a
repeat n f x = loop (n, f, x) (\(n, f, x) ->
if n == 0 then Return x else Recur (n - 1, f, f x))
main :: IO ()
main = print $ repeat 1000000 (+1) 0
As you can see you don't really need let at all. Everything that can be done by let can also be done by letrec and if you really want variable shadowing then you can just manually perform the macro expansion. In Haskell, you could even go one step further and make your code prettier using The Mother of all Monads.

Ramda currying: how to apply argument to multiple parameters

I have a situation where I need to do this:
const f = (obj) => assoc('list', createList(obj), obj)
Due to the fact that I need the argument for the second and the third parameter, prohibits me from doing something like:
const f = assoc('list', somehowGetObj())
I also tried this, but that didn't work:
const f = assoc('list', createList(__))
const f = converge(assoc, [createList, identity])
Is there a proper way to do this by currying?
Another option is
chain(createList, assoc('list'))
which you can see in action on the Ramda REPL.
Update
For further explanation of how this works, I'll use the variation which will work with the next release of Ramda:
chain(assoc('list'), createList)
to show how it matches the current signature:
chain :: Chain m => (a -> m b) -> m a -> m b
Ramda treats functions as FantasyLand Monads, and therefore thus also as Chains. So to specialize the above to functions, we have
chain :: (a -> Function x b) -> Function x a -> Function x -> b
but Function x y can be written more simply as x -> y, so the above can written more simply as
chain :: (a -> x -> b) -> (x -> a) -> (x -> b)
Then you can use these (specialized) types:
createList :: OriginalData -> YourList (x -> a)
assoc :: String -> YourList -> OriginalData -> EnhancedData
assoc('list') :: YourList -> OriginalData -> EnhancedData (a -> x -> b)
and hence
chain(assoc('list'), createList) :: OriginalData -> EnhancedData (x -> b)
const f = converge(assoc('list'), [createList, identity])

Categories