question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

flatMap and flow-based programming in Highland

See original GitHub issue

In this contrived example, I loop the output stream of the input back into itself creating a recursion-like behavior. It produces 1, 2, 4, 8, 16, 32, 64, 128, 256, 512.

_ = require('highland')
input = _([1])
input
  .doto((v)-> console.log(v))
  .map((v)-> v * 2)
  .filter((v)-> v <= 512)
  .pipe(input)

This doesn’t seem to work if I use a flatMap. It will only print out the first value, 1. My goal here is that I would like to return multiple values for each input value.

_ = require('highland')
input = _([1])
input
  .doto((v)-> console.log(v))
  .flatMap((v)-> return H([v * 2]))
  .filter((v)-> v <= 512)
  .pipe(input)

Is this a bug or is there something I need to do differently when using a flatMap?

Issue Analytics

  • State:closed
  • Created 8 years ago
  • Comments:17

github_iconTop GitHub Comments

1reaction
vqvucommented, Mar 15, 2016

I thought about it some more, and there’s a way to do recursion while still maintaining the returnPipe approach.

It doesn’t look like a flow network but accomplishes the same thing.

// Applies a transform to the stream if it is not empty.
// The reverse of `otherwise`.
function ifNotEmpty(transform) {
    return function (stream) {
        return _(function (push, next) {
            stream.pull(function (err, x) {
                if (err) {
                    push(err);
                    next();
                } else if (x === _.nil) {
                    push(null, x);
                } else {
                    var nextStream = _([x])
                        .concat(stream)
                        .through(transform);
                    next(nextStream);
                }
            });
        });
    }
}

// Recursion transform.
// transform - The main transform.
// computeReturnPipe - A transform that computes what data to feed back
//     into the recursive system. It is provided with the result of the
//     main transform.
function recurse(transform, computeReturnPipe) {
    return function (stream) {
        return stream.through(recurse2)
            .flatten();
    };

    function recurse2(stream) {
        var output = transform(stream);
        var moreData = output.observe()
            .through(computeReturnPipe)
            .through(ifNotEmpty(recurse2));

        return _([output, moreData]);
    }
}

function readDir(stream) {
    return stream
        .flatMap(function (parentPath) {
            return _.wrapCallback(fs.readdir)(parentPath)
                .sequence()
                .map(function (path) {
                    return fsPath.join(parentPath, path);
                });
        });
}

function filterDir(stream) {
    return stream
        .flatFilter(function (path) {
            return _.wrapCallback(fs.stat)(path)
                .map(function (v) {
                    return v.isDirectory();
                });
        });
}

_(['/home/vqvu/Desktop'])
    .through(recurse(readDir, filterDir))
    .each(_.log)
    .done(function () {
        console.log('done');
    });

Edit: process -> transform.

0reactions
vqvucommented, Mar 15, 2016

In the comment under “Recursion transform” you call the first argument transform but in the code it is called process

Oops! Fixed.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Highland.js
Re-thinking the JavaScript utility belt, Highland manages synchronous and asynchronous code easily, using nothing more than standard JavaScript and Node-like ...
Read more >
An Empirical Evaluation of Flow Based Programming in ... - arXiv
This paper proposes to consider Flow-Based Programming (FBP) as a paradigm for creating DOA applications. We empirically evaluate FBP in the ...
Read more >
Functional Geekery Episode 22 – LambdaConf 2015, Part 1
Programming and Math talk. Perspective on the functional programming community at LambdaConf. Interest in Clojure and Scala ...
Read more >
Generators | Scramjet
Scramjet brings generator and iterator protocol support to node.js streams and makes them easy to use as callbacks to standard methods.
Read more >
All | Alexito's World
But with patience, and thanks to the constant flow of time, California o'clock arrived and ... Casey Muratori, about Object Oriented Programming 5...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found