I am wanting to convert a list of id's into a list of Tasks, and run them concurrently, similar to Promise.all. I am aware of applicatives, but I want to apply an unknown number of tasks so I don't believe that will be the best approach.
Say I have a Task that contains an array of Task's.
Task.of([Task.of(1), Task.of(2)])
Is there anyway to fold the tasks down into a single task that will run them all, or is there a better way that I can handle the data transformation.
The snippet has data.Task included that you can copy if you want to provide an example.
http://folktalegithubio.readthedocs.io/en/latest/api/data/task/
// Task([Task])
Task.of([0, 1, 2])
.map(t => t.map(Task.of))
.fork(console.error, console.log)
<script src="https://codepen.io/synthet1c/pen/bWOZEM.js"></script>
control.async.parallel is exactly what you are looking for.
I am aware of applicatives, but I want to apply an unknown number of tasks so I don't believe that will be the best approach.
That shouldn't hold you back, arrays are traversable and sequenceA would do exactly what you wanted (though quite inefficiently). If it was implemented in folktale, which doesn't feature lists or even a control.applicative.
control.monad.sequence should have been working the same as the applicative sequence, but unnecessarily uses chain instead of ap. And data.task is problematic anyway in that ap is not derivable from chain with the same semantics.
Related
I am trying to sum up the results which got from a series of async call
let sum = 0;
for(const id of ids) {
const res = await getRes(id);
sum += res;
}
Is this a valid way to do it? Any better solution?
The code that you have written seems to be correct.
In order to validate it you can write some unit tests, I can't say how difficult it is because I don't know what getRes is doing and what external dependencies (if any) you have to mock. Generally speaking you should take the habit of unit testing your code: one of the benefits it brings to the table is offering you a way to validate your implementation.
You can also consider the idea of getting the results in parallel, this can actually speed things up. Again I don't know what getResis doing, but I suppose it performs some sort of IO (e.g.: a database query). Given the single thread nature of Javascript, when you have a bunch of independent asynchronous operations you can always try to perform them in parallel and to collect their results, so that you can aggregate them later. Please notice the bold on the word independent: in order to perform a bunch of operations in parallel they need to be independent (if they are not, the correctness of your code will be invalidated).
Since you are performing a sum of number, it is safe to compute the addends in parallel.
This is the simplest possible parallel solution:
async function sum(ids) {
const getResTasks = ids.map(id => getRes(id));
const addends = await Promise.all(getResTasks);
return addends.reduce((memo, item) => memo + item, 0);
}
Pay attention: this is a naive implementation. I don't know how many items the ids array can contain. If this number can possibly be huge (thousand of items or more) a code like the previous one could create an heavy load on the external dependency used to get the sum addends, so some precautions to limit the degree of parallelism should be taken.
I have the following problem: You are given a todo list, some items of which depend on others. Write a function that takes a subset of those todos and returns an ordered list of all the todos to complete. The given subset contains one or more of these todos.
I have written a topological sort using Kahn's Algorithm, turning the list I'm given into an adjacency list. When I have the ordered list of todos, I start adding them into another array and stop when it contains all of the items in the given subset.
This works, but I feel like it's a little bit clumsy and inefficient since I am doing a sort on the entire list and then returning a truncated version.
Any thoughts on how to make this solution a little more elegant?
Don't think of this as a topological sort. Think of this as "do dependencies first, do not do them twice." Which is simple recursive function as long as we keep track of what we will do, and what has been done.
The following Python solution may make this clearer.
def arrange_tasks(dependencies, todo, in_order=None, done=None):
if in_order is None:
in_order = []
if done is None:
done = set()
for item in todo:
# Do we need to?
if item not in done:
# Marking it done first avoids deep recursion on dependency loops!
done.add(item)
# Make sure that dependencies happened.
arrange_tasks(dependencies, dependencies[item], in_order, done)
# And now this can happen.
in_order.append(item)
return in_order
print(arrange_tasks(
{
'make a sandwich': ['buy groceries'],
'buy groceries': ['go to store'],
'go to store': []
},
['buy groceries']
))
Instead of taking a separate filtering pass, you should be able to check each task for addition to the output filteredTasks as it is processed for addition to orderedTasks.
Since the only other use of orderedTasks is to check its length, you should then be able to replace it with a counter.
This might not make your function much faster, but it will simplify your code.
I am developping a Chrome extension which, among other things, gets a (long) list of URLs in an array (or even at the console). I need to 'extract' the URLs matching the (arbitrary) patterns with the less entries in that list, completely discarding the patterns that have the most entries (say, more than 5 items).
I can't use a classic / standard regex for that, since, as I said, the patterns can be entirely different from one extension execution to another (aka they're arbitrary), but I still need to create those patterns (or ar least sort / group the list according to those patterns) in order to be able to eliminate the patterns having the most items in my list.
How do I do that in Javascript? My instinct is to either:
Make some regex patterns from the entries (but their number is also
arbitrary, so at first sight one can't know how many patterns to
create), count the items belonging to each pattern and keep only the
items that belong to patterns with no more than 5 items
Compare the items' strings between each other, the way a similar
names duplicate eliminator (e.g. dupeGuru) would and keep only
the 'similar duplicates' that have at most 5 items (but that would
probably be beyond the scope of the extension and most likely doable
in an easier / faster way)
Sort the items in the list so that the patterns with the most items
are the last, then take the first, say, 10 items in the list (aka
those who belong to the patterns with the least entries) and process
them further. This would be my preferred solution and probably one of
the fastest, but the problem is that a simple alphabetical sort
wouldn't work in every case, as the patterns with the most entries
could be alphabetically anything (plus, they could be more patterns
having lots of items).
Test case:
var list =
[
"https://www.othertext.com/textid/textid-00.htm",
"https://www.othertext.com/textid/textid-01.htm",
"https://sometext9.othertext.com/items/othertext.com/textdesc.doc",
"https://sometext9.othertext.com/textagain/moretext/158/334033.txt",
"https://sometext3.othertext.com/textagain/moretext/158/317651.txt",
"https://sometext3.othertext.com/textagain/moretext/158/336157.txt",
"https://sometext3.othertext.com/textagain/moretext/158/337299.txt",
"https://sometext3.othertext.com/textagain/moretext/158/317353.txt",
"https://sometext9.othertext.com/textagain/moretext/158/392056.txt",
"https://sometext3.othertext.com/textagain/moretext/158/144090.txt",
"https://sometext2.othertext.com/textagain/moretext/158/298691.txt",
"https://sometext3.othertext.com/textagain/moretext/158/236181.txt",
"https://sometext9.othertext.com/textagain/moretext/158/337211.txt",
"https://sometext2.othertext.com/textagain/moretext/158/337076.txt",
"https://sometext2.othertext.com/textagain/moretext/158/234047.txt",
"https://sometext3.othertext.com/textagain/moretext/158/399081.txt",
"https://sometext2.othertext.com/textagain/moretext/158/377117.txt",
"https://sometext9.othertext.com/textagain/moretext/158/311941.txt",
"https://www.othertext.com/textid/textid-02.htm",
"https://www.othertext.com/textid/textid-03.htm",
"https://www.othertext.com/textid/textid-04.htm",
"https://www.othertext.com/textid/textid-05.htm",
"https://www.othertext.com/textid/textid-06.htm",
"https://www.othertext.com/textid/textid-07.htm",
"https://www.othertext.com/textid/textid-08.htm",
"https://www.othertext.com/textid/textid-09.htm",
"https://www.othertext.com/textid/textid-10.htm",
"https://www.othertext.com/textid/textid-11.htm",
"https://www.othertext.com/textid/textid-12.htm",
"https://www.othertext.com/textid/textid-13.htm",
"https://www.othertext.com/textid/textid-14.htm",
"https://sometext9.othertext.com/sitetext/00372/00.txt",
"https://sometext9.othertext.com/items/othertext.com/randomtext/sitetext/0.txt",
"https://sometext2.othertext.com/textagain/moretext2/215/315768.txt",
"https://sometext2.othertext.com/textagain/moretext2/215/316775.txt",
"https://sometext3.othertext.com/textagain/moretext2/215/338585.txt",
"https://sometext9.othertext.com/textagain/moretext2/215/323557.txt",
"https://sometext9.othertext.com/textagain/moretext2/215/338914.txt",
"https://sometext3.othertext.com/textagain/moretext2/215/207143.txt",
"https://sometext3.othertext.com/textagain/moretext2/215/347235.txt",
"https://sometext3.othertext.com/textagain/moretext2/215/323878.txt",
"https://sometext9.othertext.com/textagain/moretext2/215/184470.txt",
"https://sometext3.othertext.com/textagain/moretext2/215/317344.txt",
"https://sometext2.othertext.com/textagain/moretext2/215/331374.txt",
"https://sometext2.othertext.com/textagain/moretext2/215/232198.txt",
"https://sometext2.othertext.com/textagain/moretext2/215/275001.txt",
"https://sometext2.othertext.com/textagain/moretext2/215/396962.txt",
"https://sometext2.othertext.com/textagain/moretext2/215/339011.txt",
"https://sometext9.othertext.com/textagain/moretext2/215/303454.txt",
"https://sometext3.othertext.com/textagain/moretext2/215/336118.txt",
"https://sometext9.othertext.com/textagain/moretext2/215/339482.txt"
];
In this case, I would like to keep only:
var result =
[
"https://sometext9.othertext.com/items/othertext.com/textdesc.doc",
"https://sometext9.othertext.com/sitetext/00372/00.txt",
"https://sometext9.othertext.com/items/othertext.com/randomtext/sitetext/0.txt"
];
since these items belong to the patterns with 5 items at most.
A simple code sample or an explained method would be great.
Recently I've come across with a school of thought that advocates replacing conditionals(if/switch/ternary operators, same below) with something else(polymorphism, strategy, visitor, etc).
As I'd like to learn by trying new approaches, I've then revised some of my Javascript codes and immediately found a relevant case, which is basically the following list of ifs(which is essentially the same as a switch/nested ternary operators):
function checkResult(input) {
if (isCond1Met(input)) return result1;
if (isCond2Met(input)) return result2;
if (isCond3Met(input)) return result3;
// More conditionals here...
if (isCondNMet(input)) return resultN;
return defaultResult;
};
Shortly after I've come up with trying a predicate list instead.
Assuming that checkResult always return a String(which applies to my specific case), the above list of ifs can be replaced with a list of predicates(it uses arrow function and find which are ES6+ features though):
var resultConds = {
result1: isCond1Met,
result2: isCond2Met,
result3: isCond3Met,
// More mappings here...
resultN: isCondNMet
};
var results = Object.keys(resultConds);
function checkResult(input) {
return results.find(result => resultConds[result](input)) || defaultResult;
};
(On a side note: Whether checkResult should take resultConds and defaultResult as arguments should be a relatively minor issue here, same below)
If the above assumption doesn't hold, the list of predicates can be changed into this instead:
var conds = [
isCond1Met,
isCond2Met,
isCond3Met,
// More predicates here...
isCondNMet
];
var results = [
result1,
result2,
result3,
// More results here...
resultN
];
function checkResult(input) {
return results[conds.findIndex(cond => cond(input))] || defaultResult;
};
A bigger refactoring maybe this:
var condResults = {
cond1: result1,
cond2: result2,
cond3: result3,
// More mappings here...
condN: resultN,
};
var conds = Object.keys(condResults);
function checkResult(input) {
return condResults[conds.find(cond => isCondMet[cond](input))] || defaultResult;
};
I'd like to ask what're the pros and cons(preferably with relevant experience and explanations) of replacing a list of conditionals with a predicate list, at least in such cases(e.g.: input validation check returning a non boolean result based on a list of conditionals)?
For instance, which approach generally leads to probably better:
Testability(like unit testing)
Scalability(when there are more and more conditionals/predicates)
Readability(for those being familiar with both approaches to ensure sufficiently fair comparisons)
Usability/Reusability(avoiding/reducing code duplications)
Flexibility(for example, when the internal lower level logic for validating inputs changes drastically while preserving the same external higher level behavior)
Memory footprint/Time performance(specific to Javascript)
Etc
Also, if you think the predicate list approach can be improved, please feel free to demonstrate the pros and cons of that improved approach.
Edit: As #Bergi mentioned that Javascript objects are unordered, the ES6+ Maps may be a better choice :)
In general, putting business logic (like these predicates) in separate objects always improves testability, scalability, readability, maintainability and reusability. This comes from the modularisation inherent to this OOP design, and allows you to keep these predicates in a central store and apply whatever business procedures you want on them, staying independent from your codebase. Essentially, you're treating those conditions as data. You can even choose them dynamically, transform them to your liking, and work with them on an abstract layer.
Readability might suffer when you need to go to certain lengths to replace a simple a short condition with the generic approach, but it pays of well if you have many predicates.
Flexibility for adding/changing/removing predicates improves a lot, however the flexibility to choose a different architecture (how to apply which kind of predicates) will worsen - you cannot just change the code in one small location, you need to touch every location that uses the predicates.
Memory and performance footprints will be bigger as well, but not enough to matter.
Regarding scalability, it only works when you choose a good architecture. A list of rules that needs to be applied in a linear fashion might not do any more at a certain size.
I am very much a noob at this, and regarding readabillity and usabillity I prefer the latter but it's a personal preference and I'm usually backwards so you shouldn't listen to me.
The conditional approach is more portable, I mean easily ported to non-object oriented languages. But that may never happen, and even if it does the people doing that kinds of things probably has tools and experience so it shouldn't be an issue. Regarding performance I doubt there will be any significant differences, first one looks like branching and second kind of like random access.
But as I said, you shouldn't listen to me as I'm just guessing
I'm implementing a mutation testing tool for JavaScript.
AST is modified and test cases are executed against the modified code.
After running the test cases, I want to restore the modified AST to the original one so that I can repeat the mutation process.
But, I have no idea how to restore it. Any help?
Rhino API Documentation
I don't know Rhino specifically so I don't know if it offers specific help for this. But in general you can straightforwardly do this yourself, by keeping track of the changes you changes you make, as "anti-changes". This scheme works for any system of ASTs, not just Rhino.
A tree consists of nodes, and relations between a node and its children.
To construct a tree, you can execute commands to create a node, create its children, and link them together. Surely the Rhino API offers primitive support for this.
To re-construct a tree at a later time, we merely make a list of actions to accomplish based on node construction, and child connection/disconnection.
So imagine the following tree:
1:*
/ \
2:+ 3:[]
/ \ / \
4:x 5:17 6:a 7:i
I've marked the nodes as n:t where n is a node number and t is the node type or literal value. We will number the children of a node left to right as 1, 2, ...
Now we modify ("mutate") the tree by replacing 2:+ with a new node 8:mod and 5:17 with 9:j. Our actions to do this are abstractly, in order:
disconnect(2,1); // disconnect node N from its Mth child
disconnect(2,2);
disconnect(1,1);
delete(2);
delete(5);
n1=create(mod); // node 8
n2=create(j); // node 9
connect(1,1,n1); // connect node 1 child 1 to n1
connect(n1,1,4);
connect(n1,2,n2);
We record the inverse actions in reverse order in an (transaction) "undo" list to be processed later:
[ [disconnect,n1,2],
[disconnect,n1,1],
[disconnect,1,1],
[delete,n2],
[delete,n1],
[create,n5,17],
[create,n2,+],
[connect,1,1,n2],
[connect,2,2,n5],
[connect,2,1,4] ]
This list can be "executed" by looping through the elements in order and simply doing what the elements say with a trivial interpreter.
And it is easily constructed; for every tree mutation operation, we push a new inverse operation on the front of of the undo list. We can make this easy by replacing our tree mutation operations by tree-mutate-and-remember-inverse operations, e.g.,
fn disconnect_and_remember_inverse(node,child) {
push(undo_list,[connect,node,child,nth_child(node,child)]);
disconnect(node,child);
}
Where a "delete" operation is used, the inverse will have either recreate the corresponding node type, or, if you will always restore the tree,
simply NOT delete the node and remember it in the "undo" list:
[ [disconnect,n1,2],
[disconnect,n1,1],
[disconnect,1,1],
[delete,n2],
[delete,n1],
// [create,n5,17],
// [create,n2,+],
[connect,1,1,2],
[connect,2,2,5],
[connect,2,1,4] ]
The place this may get you into trouble are compound tree-smashing operations implemented by Rhino; you obviously want those operations to call these remember_inverse procedures. That may not be convenient; you'll
have to replicate those procedures with your own equivalents.
Details and subtleties left to the reader. (I'm not a JavaScript coder either, so forgive any syntax sins I committed).