How do I handle the file system? I'm trying to get my head around asyncronous programming in node.js.
My example is reading all the files from a directory.

I know I can avoid asyncronous programming by using the syncronous methods:

var fs = require('fs');

names = fs.readdirSync(".");
for(i in names) {
  fileinfo = fs.statSync( names[i] );
  if( fileinfo.isFile() ) console.log( names[i] + " has size " + fileinfo.size );
};


I know how to write it in the classic node style:

fs.readdir(".", function (err, names) {
  if (err) throw err;
  names.forEach(function(n){
    fs.stat( n, function(err, fileinfo) {
      if( fileinfo.isFile() ) console.log( n + " has size " + fileinfo.size );
    });
  });
});


But now I'm trying "functional reactive programming" with bacon.js and I'm not sure if I really get it.  This is my first sketch:

var fs = require('fs')
  , Bacon = require("baconjs").Bacon;

fs.readdir(".", function (err,names) {
  if (err) throw err;
  Bacon.fromNodeCallback( fs.stat_with_filename, Bacon.fromArray(names) )
    .filter(".isFile")
    .onValue(function(stat) {
      console.log(stat.filename + " has size " + stat.size);
  });
});


But I had to monkeypatch fs to get the filename inside the stat object to achive this:

fs.stat_with_filename = function( filename, callback ) {
   fs.stat( filename, function (err,stats) {
     stats.filename = filename;
     callback( err, stats );
   });
};


Is there a better way to write this in node + bacon?
If you want to expose directory contents with stats as a Bacon EventStream or a Property, you can use the combine-family of functions to combine the filename and stats without monkey-patching:

var fs = require("fs")
var Bacon = require("../dist/Bacon.js")

// statsForFile :: String -&gt; Property { filename :: String, stats :: Stats }
function statsForFile(filename) {
  return Bacon.combineTemplate({
    name: filename,
    stats: Bacon.fromNodeCallback( fs.stat, filename )
  })      
}


You can expose directory contents as a stream of filenames:

// directoryContents :: String -&gt; EventStream String
function directoryContents(dir) {
  return Bacon.fromNodeCallback(fs.readdir, dir)
    .flatMap(function(names) { return Bacon.fromArray(names)})
}


Then you can compose these two like

function statsForDir(dir) {
  return directoryContents(dir).flatMap(statsForFile)
}


And see what happens:

statsForDir(".").log()


So that's how you can compose these things asynchronously using Bacon.js and FRP. This is not a prime example of where FRP is really useful yet, but when more composition is involved the benefits will be greater. Hope this helps!