Besides lazy execution, are Tasks and Promises pretty much the same thing?
When I refer to a task, I refer to a class that is in its most basic behavior like the following:
class Task {
constructor(then) {
this.then = then;
}
map(mapper) {
return new Task((resolve, reject) => this.then(
x => resolve(mapper(x)),
reject
))
}
flatMap(mapper) {
return new Task((resolve, reject) => this.then(
x => mapper(x).then(resolve, reject),
reject
))
}
}
What type of (class?) is a task/promise? I'm learning about functional programming approaches, but I don't think I've gotten to this type yet. Is it a type of monad?
Yes, the key thing is a monadic bind, or a flatMap in your case that has the signature:
Task A -> A -> Task B -> Task B
With promises - that's the then method that:
Promise A -> (A -> Promise B) -> Promise B
this onFulfilled return value
In fact, both are instances of the Continuation Monad. Lots of other things (like Rx streams) are instances of the continuation monad.
Promises in JavaScript however are specced with a slightly different (and uglier, for arguably practical reasons) signature with it being possible to also return a plain value from then, and there are exception semantics involved.
There was a push for more "monadic" promises back in 2013 when they were specced, but it failed. The current promises in JavaScript aren't really "monad"s per-se.
A.promises are one refactoring step further than callback.just that.
if you have a function
const f = x => x * x ;
1) Use Callback and remove return type
you can pass a callback and remove the return type. This the famous Continuation-passing style
const f1 = (x,callback)=>callback(x*x);
What if we curry the action and return it as a result ?! we could do this :
const squareCont = (x)=>callback=>callback(x*x);
if you look at this for a long time and rename callback to resolve you will see that this is actually a promise.
//i rewrited it to make it clearer
var squareCont = function(x){
return function (resolve){return resolve (x*x);}
}
[Side Note : we could make it into a Promise if we enclose the callback into an object that exposes a then function like that :
const squarePromise = (x)=>({then:callback=>callback(x*x)});
squarePromise(2).then(r=>console.log(r))
check the fiddle here]
B.Task is the Coninuation Co-Monad . Because i cannot summarize it here you can read in more detail here : Promises & Continuation Monad in JavaScript
and here
Async/await a.k.a Continuation Co- Monad in JavaScript
Related
I'm trying to write a function composition that partially applies an argument at each step and ends up calling a curried two-argument function.
There is a set of example functions to compose. I removed the calculations that there are supposed to do as they are not relevant to the problem but let's assume that every argument is required.
const getDayLimit = () => {
return 10
}
const getIpCount = ip => dayLimit => {
return 99
}
const getIp = (deviceId, headerIp) => {
// TODO: use Result monad to handle errors
if (!deviceId && !headerIp) {
throw new Error('Ip not provided')
}
return deviceId || headerIp
}
And the composition attempt:
const validateIp = R.compose(
f => f(getDayLimit()),
getIpCount,
getIp
)
validateIp(1, 2)
In the first step, getIp received two values and based on them returns an ip that is then partially applied to getIpCount, now the composition return a function that expects the dayLimit argument that needs to be computed first.
The plain way of doing this could be: f => f(getAccountLimit()).
I'd like to remove such function creation f => f... and pass it point-free.
Here's a helper function that solves this but is not handling all cases such as passing arguments to the result function:
const applyResult = result => f => R.compose(f, result)()
then I could do:
const result = R.compose(
applyResult(getDayLimit),
getIpCount,
getIp
)
It seems too hacky for me and not substantial for my further use. I'd rather avoid writing my own helper function for this kind of problem.
Is there a functional way of computing arguments before partially applying them to a function? It seems to be a pretty common case in my mind, though perhaps I'm not thinking about the problem correctly.
Is my thinking incorrect about this problem and function composition?
What is a good approach to handling such a case with a function with two parameters in a composition?
Can this case of partially applying function arguments with each step be handled in a function composition?
Thank you!
I think I would use a continuation which, as I understand it, represents a computation that has been interrupted:
const cont = x => f => f(x);
With a continuation, you get x before f. Instead of doing f(x) you do cont(x)(f) which behind the scene just does f(x) for you.
At the time of composing the functions together you already know the value of x which is getDayLimit(), you just don't know the value of f yet which is known only when result is applied to the first two initial parameters.
So here's what I'd do:
const result = R.compose( cont(getDayLimit())
, getIpCount
, getIp);
Is there a functional way of computing arguments before partially applying them to a function?
I would simply note that you apply a function to a value (not the other way round)
This question already has an answer here:
How to chain and share prior results with Promises [duplicate]
(1 answer)
Closed 6 years ago.
Is there a better way to do this?
let foo;
return functionA().then(result => {
foo = result;
return functionB();
}).then(bar => {
return functionC(foo, bar);
});
Notice that the result of functionA is required input to functionC. Using a variable outside the promise scope works fine, but it feels kinda icky. Is there a clean idiomatic way to do this?
Please note that I do not have the opportunity to change the API of any of the functions I am calling.
You could try using Promise.all() which you can pass an array of promises and it provides an array of responses within the then() callback when all promises passed in have resolved. You can access those array values to pass into functionC:
Promise.all([functionA, functionB]).then(values => functionC(values[0], values[1]));
Might be a little cleaner (without nesting) as it doesn't look like the response from functionA needs to be passed into functionB.
Otherwise, nesting would look like:
return functionA().then(foo => {
return functionB().then(bar => {
return functionC(foo, bar);
});
});
One option is, as Alexander Staroselsky writes, to use Promise.all(functionA(), functionB()). This runs the two functions simultaneously. If that's what you want to happen, you can use that answer. If, however, you want them to happen one after the other and then also be able to pass the result onto another handler, you can do this:
function functionA() {
return new Promise(resolve => resolve(1));
}
function functionB() {
return new Promise(resolve => resolve(2));
}
function functionC(first, second) {
return first + second;
}
functionA()
.then(result => Promise.all([result, functionB()]))
.then(function([first, second]) {
return functionC(first, second);
})
.then(result => {
console.log(result);
});
The functions are obviously simplified -- but the lovely thing about Promises is that that doesn't matter: we don't care how complex they are or how long they take. Yay Promises!
The clever thing is that Promise.all doesn't mind if the values you pass are not Promises. If they are any other value, they are treated as a Promise that is resolved immediately. (In the same way that you can do Promise.resolve(42).then(...).) So we can do Promise.all([result, functionB()]). This says "give me a Promise that is resolved when you have a final value for both result and functionB() and pass both values on". That is immediately in the case of result and at some unspecified time in the case of functionB.
The returned values are then passed as an array to the next then function.
.then(function([first, second]) {
return functionC(first, second);
})
This then receives the values as an array (see the use of destructuring in the parameter list) and sends those values on to functionC. We then do one last then function to show the result.
I came across the following code for a callback function. I understand the code, but I can't wrap my head around it. It just seems so counterintuitive.
function greet(name,callback1){
callback1(name)
}
greet("John Cena", function (somerandomName) {
console.log(somerandomName);
return someRandomName;
}); // Output is John Cena and undefined.
This is what I have understood from the code:
We define a function greet, which takes 2 parameters name and callback1. Then we say that callback1's parameter is name. We don't return anything in the greet function, why?
And when we invoke the greet function we pass the 2nd parameter as an Anonymous function whose parameter is someRandomName. Then we console.log(someRandomName).
I added the return someRandomName, but this return did not work and I got the printed statement followed by undefined
Can someone please explain this in simple words, This just seems so counterintuitive.
So I think it is important to understand that functions themselves can be parameters.
In this example you pass a string as the first parameter and then a function that takes that string as a parameter as the second parameter.
Functions do not always need to return something. Often a function might perform a manipulation on the dom, fetch data, configure something or alter pre existing variables. Of course you can return something if that is what is needed.
Adding return like you did does not do much. In order to actually return the name value you would have to write the original function like this.
function greet(name,callback1){
return callback1(name)
}
Then you could do something like this
var wrestler = greet("John Cena", function (somerandomName) {
console.log(somerandomName);
return somerandomName;
});
console.log(wrestler) // prints John Cena
Its sort of an weird example since it serves no real purpose. Something like this might help you see whats going on.
function greet(name, callback) {
callback(name)
}
greet('John Cena', function(name){
console.log('Hello ' + name) // prints Hello John Cena
})
OR return something and use it to manipulate dom
function greet(name, callback) {
return callback(name)
}
var greeting = greet('John Cena', function(name){
return 'Hello ' + name
})
document.getElementById('message').innerHTML = greeting
// somewhere in HTML...
<h1 id='message'></h1>
Either way at least we are doing something to the first parameter now. And the things that you can do with callbacks are limitless.
Callbacks are a fundamental feature of javascript. They come into play alot when the first part of the function is asynchronous, such as a call to an api or database. In this case the first part would be the call to the database and the callback will not be fired until a value is obtained from the initial call. Recently, this callback pattern is being used less due to Promises, but callbacks are still useful.
So an example of a generic api call from a frontend to a backend. This would typically be done using the Fetch Api or with a library like Request or Axios. Just remember, the first function that is calling an endpoint takes some amount of time to execute and get data. The callback will not fire until that data is returned. Of course there would be a function on the backend that sends either an error or data back to the callback. I dont want to over complicate things, rather just give an idea of what callbacks are often used for.
function getDataFromBackend(endPoint, callback) {
callback(error, data)
}
getDataFromBackend('/api/user', function(error, data) {
if (error) {
// handle error - show user error message in ui, etc
}
// do something with data - such as display welcome message to user, etc
})
I would suggest working with callbacks for practice. I find that when I use Node, or build an app with a frontend and backend I implement callbacks a lot for, since there is a lot of asynchronous communication happening. Hope I answered your questions.
First, you have return someRandomName but your parameter is called somerandomName. Variables are case sensitive; that's why your return value is different from what you want.
Your question is Why don't we return anything in the greet function. The answer is "I have no idea." You could return something. Some functions return things; some functions don't. That has nothing to do with the callback arrangement here.
function greet(name,callback1){
return callback1(name)
}
var finalResult = greet("John Cena", function (someRandomName) {
console.log(someRandomName);
return someRandomName;
});
Now finalResult will be "John Cena".
If it helps at all, anywhere you're using an anonymous function, you could just as easily use a named function. (It's often uglier in practice, but for the sake of understanding the concepts...)
function greet(name,callback1){
return callback1(name)
}
function myGreeterFunction(someRandomName) {
console.log(someRandomName);
return someRandomName;
});
var finalResult = greet("John Cena", myGreeterFunction);
Now it's perhaps easier to see that callback1(name) is the same thing as saying myGreeterFunction(name) in this case.
This is a pretty dated approach to JavaScript and you are totally right that it's counter intuitive. In this particular example there's no advantage of writing this with a callback and probably should be written as a promise,
greet("John Cena")
.then(() => {
return 'Next Action'
})
.then(nextAction => {
console.log(nextAction)
})
And as #mark-meyer pointed out this approach would be required if you had an asynchronous event.
Actually an AWS Lamda function actually has an optional callback defined as it's third argument. exports.myHandler = function(event, context, callback) {}. Which to be brutally honest I think is only there to cover cases where third party libraries aren't promised based.
Whilst passing a callback to a function is probably never the correct approach, there's still cases where passing a function to a function is valuable. Perhaps in a pub/sub system.
const events = {}
function subscribe (event, func) {
if (events[event]) {
events[event].push(func)
} else {
events[event] = [func]
}
}
function publish (event) {
if (events[events]) {
events[event].forEach(func => func())
}
}
And if you are writing with a fp approach link in RamdaJs chaining functions is going to be a huge part of what you write.
Does that clear things up a bit #pi2018?
The general technique is called continuation-passing style – contrast with direct style.
The technique does allow for some interesting programs to emerge. Below, we have two ordinary functions add and mult. We write two programs using cont which allows us to string these functions together, where each step is
the continuation of the one before it.
const cont = x => k =>
cont (k (x))
const add = x => y =>
x + y
const mult = x => y =>
x * y
cont (1) (add (2)) (mult (3)) (console.log) // 9
// 1 ->
// x => 2 + x
// cont (3) ->
// x => 3 * x
// cont (9) ->
// x => console.log (x)
// cont (undefined)
We can sequence as many operations as needed –
const cont = x => k =>
cont (k (x))
const add = x => y =>
x + y
const mult = x => y =>
x * y
cont (2) (mult (2)) (mult (2)) (mult (2)) (mult (2)) (console.log) // 32
// 2 ->
// x => 2 * x
// cont (4) ->
// x => 2 * x
// cont (8) ->
// x => 2 * x
// cont (16) ->
// x => 2 * x
// cont (32) ->
// x => console.log (x)
// cont (undefined)
Continuation-passing style can be used to implement concurrent programs, but JavaScript provides a better native concurrency primitive now, Promise. There's even new async and await syntax to make working with Promises easier.
As wikipedia notes, continuation-passing style is used more by compilers and less by programmers. If you're trying to write concurrent programs, I would highly recommend you use Promises instead. Later versions of Node include util.promisify which allows users to convert a continuation-passing style function to a Promise-returning async function.
I am composing a series of function but I wonder what's the best way to achieve what I want first this is how I compose:
const composeP = (...fns) => fns.reduce((f, g) => async (...args) => f(await g(...args)))
const profileSummary = profileData => composeP(createProfileSummary, getMKAProfile)(profileData)
now what I want is to do a check and if profileData which is my input is a certain string e.g. "cantbesearched" I want to return a value immediately to "profileSummary" variable instead of executing previous functions...
so is it possible to create a "filterWords" function, put it in front of the composition like this:
const profileSummary = profileData => composeP(createProfileSummary, getMKAProfile, filterWords)(profileData)
and if certain words are detected, skip previous functions on the left then return a value.
Is it possible to create a "filterWords" function to be put it in front of the composition?
No. What you want to do is branching, which is not possible with function composition.
What you can do is compose functions that work on a type which provides an error path, like Maybe or Either. (You can also consider exceptions as a builtin error path for every type, so just throw).
Oh wait, you already are doing that! You didn't write a plain function composition compose, you wrote composeP which uses monadic Kleisli composition - and promises do have such an error path:
function filterWords(word) {
return word == "cantbesearched"
? Promise.reject(new Error("filtered for your safety"))
: Promise.resolve(word);
}
I know this example is quite contrived but I am still curious wether or not this can be considered a pure function:
const addAsync = (x, y) => new Promise((resolve, reject) => {
setTimeout(
() => resolve(x + y),
Math.random() * 1000
);
});
Every call to this function returns a Promise that resolves to the sum of the two arguments. The promise resolves after a random amount of time between 0 and 1 seconds.
For all intends and purposes, this seems to be perfectly pure, meaning that I can treat this function in tests or in my code as a pure function (a, b) -> Promise(a + b). However, since we are using Math.random(), we cannot transform this function into a lookup table and back without losing functionality (we lose the delay). So can this considered to be pure or not?
I believe it can be consider as a pure function. A pure function is defined as a function where the return value is only determined by its input values, without observable side effects.
In this case the output is only determined by its input and it doesn't produce any side effects. The fact that it takes different amount of time to compute the result should not have an effect on its pureness.
But i would warn that i am not a functional programming expert and i may be wrong
Let's clarify the term pure first. Purity means referential transparency, ie. one can replace an expression with its evaluated result without altering the behavior of the program. Here is an action that returns a promise. To visualize the computation I perform logging as a side effect:
const addAsync = (x, y) => new Promise((r, e) => {
setTimeout(
z => (console.log(z), r(z)),
Math.random() * 1000,
x + y
);
});
console.log("before");
addAsync(2, 3);
console.log("after");
// logs
"before"
"after"
5
Next I substitute the expressionaddAsync(2, 3) with its result, which is a fulfilled Promise containing 5. Since there is no Promise literal in Javascript, I represent an already settled promise with Promise.resolve:
console.log("before");
Promise.resolve(console.log(5), 5);
console.log("after");
// logs
"before"
5
"after"
Looking at the code there seems to be no difference. The expression addAsync(2, 3) yields a settled promise (kind of like Promise(5)).
Promise.resolve(console.log(5), 5) on the other hand represents this very settled promise. But by observing the console.log side effects we can see that the evaluation order has changed, that is a function that returns a promise actually alters the behavior of a program. Hence such a function is impure.
No.
I would argue that the state the returned Promise is in, is unknown to us, just like the life of the cat of Schroedinger. The Promise is either resolved or rejected or pending, but we cannot predict when it is in what state. A snippet that outlines this:
let a = 0;
addAsync(1,2).then(res => a += res).then(console.log);
addAsync(0, 1).then(res => a += res).then(console.log);
If addAsync would be pure, it would always log the same.
Simple answer is NO. But I offer a simple way to push the impurity elsewhere
In the pure part of your code
const incRandomDelay = addAsync.bind(null,1)
Now somewhere in the effects part of your code
incRandomDelay(10).then( sum => writeToFile(sum) )