At programming styles course we are asked to implement some code in both, "continuation-passing style" and "candy factory style".
The book we are reading is "Exercises in programming styles" by Cristina Videira Lopes (chapter 5 and 8).
We are asked to implements the examples codes of the book in another language(in the book is in Python, now I am using Javascript).
In order to understand my problem, i will show you the two main differences showed in the book:
Candy Factory Style
#!/usr/bin/env python
read_file(path_to_file):
"""
Takes a path to a file and returns the entire contents of the
file as a string
"""
with open(path_to_file) as f:
data = f.read()
return data
def filter_chars_and_normalize(str_data):
...
.
.
.
print_all(sort(frequencies(remove_stop_words(scan(
filter_chars_and_normalize(read_file(sys.argv[1]))))))[0:25])
Continuation-Passing Style
#!/usr/bin/env python
def read_file(path_to_file, func):
with open(path_to_file) as f:
data = f.read()
func(data, normalize)
def filter_chars(str_data, func):
pattern = re.compile(’[\W_]+’)
func(pattern.sub(’ ’, str_data), scan)
.
.
.
read_file(sys.argv[1], filter_chars)
Javascript
const fs = require('fs');
var myArgs = process.argv.slice(2);
function read_file(path_to_file,callback){
fs.readFile(path_to_file, "utf-8",(err, data) => {
if (err) throw err;
callback(data);
});
}
function string_to_lower(str_data,callback){
var data = str_data.toLowerCase()
callback(data)
}
.
.
.
function TermFrequency(){
read_file(myArgs[0],function(result){
string_to_lower(result, function(result2){
remove_non_alphanumeric(result2,function(result3){
remove_stop_words(result3,function(result4){
frequencies(result4,function(result5,result6){
sort(result5,result6,function(result7,result8){
write_out(result7,result8)
})
})
})
})
})
})
}
From what I understood, and from the examples from the book, what's written above in Javascript, is Continuation passing, since a function is passed as parameter. But at the same time, in order to call the main function you use the same call "in pipeline style" as the candy factory.
How is it possible to achieve the candy factory style given the code written in JS above? Is that code (which is based on callbacks) candy factory or continuation-passing style? How can I write the code above, without making use of callbacks and at the same time trusting JS?
I think you are confusing 2 things. Candy style is more commonly referred to as function composition. That is where the output of one function is the input for the next one.
h(1)
outputs a value and that is the input forg
which outputs a value and is the input forf
.that is different that the callback style used in Javascript for asynchronous operations.
Where
f
takes a value, processes it and callsg
at a later time.Often in JavaScript you'll need to handle asynchronous operations but you only need callbacks(continuations) in those situations. Functions like your
stringToLower
only need to return data.If you were to adjust your code to follow those rules, then you could do something more familiar:
Knowing that this is composition we could use another function to simplify this even more.
and we can use it like this:
Now this may look foreign but let's walk through it. The function compose takes a list of arguments called
fns
. The...
(the rest operator) just takes individual arguments and puts them into an array. You'll notice that thecompose
function returns another function. Socompose(omg)
would return another function waiting for avalue
. When you provide the value then the function goes off running. We callcompose
with a list of functions and it returns a function waiting for a value. We assign that function to theconst
processFile
. Then we do our async operation and setprocessFile
as the callback. The callback (ourcompose
function) receives the value it's waiting for and then does all the processing synchronously.Hope this clears a few things up. I'd also recommend looking into promises so you don't have to deal with callbacks.
JavaScript is interesting because it is natively an asynchronous language. Python on the other hand is not. That means in python you can us eboth styles but in Javascript there are times when you must use both styles.
Also, keep in mind that, in JavaScript, there are callbacks, with which we built promises, with which we built Async/Await. Understanding the callback flow is imperative to being able to use the highler level tools more effectively.