Hacker News new | past | comments | ask | show | jobs | submit | CrossEye's comments login

I wonder if whatever is left of Netscape can sue Microsoft now over JScript...


And many of us have gained a great deal by having you publish on the side.

Thanks, raganwald!


as inglor said, this depends on strict mode:

    > var isboxed = (function() {"use strict"; return function isboxed() {return this instanceof Number;}}());
    > isboxed.call(5);
    false


No, in fact the real problem has been that too many incompetent people were far too certain about how to use it.


(Disclosure: one of the authors of Ramda here, so I may well be biased toward a very different approach.)

This is an interesting approach, but I get caught right at the beginning, where you say "What you'd really want to do is this:

    items
      .filter(isOk)
      .map(toOtherType)
      .flatten()
      
      
But what I really want to do is build a reusable function:

    var process = seq(filter(isOk), map(toOtherType), flatten);
    
So I can at my leisure call

    process(items);
    
Or later put `process` in another sequence, or do something like:

    map(process, groupsOfItems)
    
And I don't see that Trine helps with that. Am I missing the way to use Trine to build functions, or do I simply have to wrap up a Trine construct in a function that takes a parameter, does its Trine magic, and returns that result?


I believe you showed in one of your demonstrations (or someone else showing ramda), a very simple elegant example:

    > sum = reduce(add, 0)
    > sum([1,10,20])
With something like trine, composition can only happen really happen at usage-time, while with Ramda it allows you to reason about the operations separate from the data. I suppose trine could achieve the same by further complicating with some sort of dummy data:

    sum = __placeholder__.reduce(add, 0);
    [1,10,20].::sum()
But this gets difficult because __placeholder__.reduce itself needs to return something that can be chained (certainly doable to return a function that is also a dummy object I suppose?). But anyways, to me this starts looking more and more complex, and making it harder to reason about constructing (composing) NEW functions from existing ones.


That is ceratainly one of my standard examples.

The best answer to this seems to be simply:

    var sum = ls => ls.reduce(add, 0)
ISTM that this is neither as elegant nor as easy to reason about, but it's also not horrible. It really moves away from the easy association that Ramda makes between

    var currentTotal = reduce(add, 0, nbrs);
and

    var sum = reduce(add, 0); //=> :: [Number] -> Number
Of course this arrow syntax is ES6 (or transpiler) only, but the library is predicated on that notion. Ramda is a bit of an oddity, still maintaining compatibility with ES3 - ES6.


Trine can actually already do this particular example:

    sum = reduce::partial(add, 0);
    [1,10,20]::sum();


(Disclosure: big fan of Ramda here)

That's exactly where I got caught too. I just don't see why I really want to do it that way at all.

My favorite thing about Underscore/Lodash/Ramda is function composition. This seems like a (syntactical) move away from that . . .


(Disclosure, Trine author here, and also admittedly very inspired by Ramda.)

I actually used Ramda quite extensively a while back, because I was convinced it was the right way. However, a while after looking at stack traces that lead to Ramda and not even myself understanding my where each parameter in my own code goes, I decided to stop using it and also dropped these features from Trine. Trine has partial, and that's as far as magic goes, in fact I wanted to make it as far from magical as possible. I think plain old functions are the best form of function composition, albeit I'd love for the syntax to be terser. They're easy to read and easy to reason about, also easy to reorder, no need for higher order functions that go in the middle.


It's a funny world. Each of us is looking at the other library thinking there's too much magic involved. :-)

Ramda is [considering a technique][1] that would significantly reduce call stacks. But there is nothing likely to help with you understand parameter orders of your functions. Many users annotate their functions with something like Haskell signatures.

Thank you for bringing forth another interesting library. I'll be following your progress. Best of luck!

[1]: https://github.com/ramda/ramda/pull/907


> It's a funny world. Each of us is looking at the other library thinking there's too much magic involved. :-)

Heh - I think what feels like magic is the syntax that Trine is presuming, which admittedly might seem magical before trying it out. :) The library itself is just a collection of very primitive methods (with the exception of partial()).

> Ramda is [considering a technique][1] that would significantly reduce call stacks.

That's good to hear! But what I'd really like to see is something that would make the stack trace have a reference to the function definition site, e.g. if I have an error like

    var getIds = map(prop("id"));
    var ids = getIds([{ id: 1 }, null, { id: 2 }]);
the stack trace would also show the definition site of getIds. This is what I get when I compose functions just using the vanilla JS syntax:

    function getIds (items) {
      return items.map(function (item) {
        return item.id; // the stack trace will point here, and I can also add a breakpoint here without it stopping on every unrelated prop() call
      });
    }
Like I mentioned on several occasions here, I'm hoping for JS to get simpler unbound function syntax, which would work well with Trine, and still have the aforementioned benefits:

    let getIds = -> this::map(-> this.id);
> Best of luck!

Thank you, and likewise! <3


Agreed. And btw thank you for Ramda, which is a very beautiful thing. Too sad in day-to-day web development lodash is just enough.


That's not sad. Use the tools that work for you.

It was finding that those tools were no longer supporting the way I wanted to work that got me started on Ramda. I'm guessing the same is true for the author of Trine.


and thanks again for Ramda .. I use it daily for real work, back and front end.


If you mean using frameworks to display data, then yes. For anything substantial I'd use ramda over lodash.


Why not both? lodash is modular so you can use the bits you need. There's also a flavor with auto-curried iteratee-first/data-last methods too https://www.npmjs.com/package/lodash-fp


With Trine this would be

    function process () {
      return this
        ::filter(isOk)
        ::map(toOtherType)
        ::flatten();
    }
and then later:

    groupsOfItems::map(process);
Granted, the `flatten` function is not in the Trine yet, somehow forgot that from the initial release.


Ok, that helps make it a bit more palatable to me.

Thanks for the information.

One question, though: How do user functions interact in here? If you didn't include `flatten`, but I had my own version of it, would it be straightforward for me to build `process` using my own `flatten`? Do I have to modify some Trine objects, or can I use some simple function references?

Obviously I haven't yet actually dug into the Trine code. Perhaps this weekend.


Happy to help!

Yes, you can use just simple function references, e.g. you could just define flatten as so

    function * flatten () {
      for ( const item of this ) {
        yield * item;
      }
    }
And it would work just like it was part of Trine - in fact that's probably how it's going to be implemented in Trine. The chaining is not a feature of Trine, but the function bind syntax proposal ( https://github.com/zenparsing/es-function-bind ), Trine has merely been designed to work well with this syntax.


Seems like you could just do

  var process = items => items.filter(isOk).map(toOtherType).flatten()


The difference starts to show when you want to partially apply some values.

    // process1 :: (Item -> Bool) -> [Item] -> [OtherType]
    // process2 :: [Item] -> [OtherType]
    process1(isOk, items); //=> [otherType1, otherType2, ...]
    process2(items); //=> [otherType1, otherType2, ...]

    
    var processR1 = seq(filter, map(toOtherType), flatten);
    var processR2 = processR1(isOk);

    
    var processT1 = (isOk, items) => items.filter(isOk).map(toOtherType).flatten()
    var processT2 = items => processT1(isOk, items)
That's why I'm wondering if there's some easier way to do this.


I believe you can use partial() from this post[1] to do something like this:

  var processT1 = (isOk, items) => items.filter(isOk).map(toOtherType).flatten();
  var processT2 = partial(processT1, isOk);
http://benalman.com/news/2012/09/partial-application-in-java...


"governments and private companies" certainly do not preclude committees. Quite to the contrary, in fact.


Disclosure: self-submission


Yes, and those damned Italians still refuse to switch to English too!


Very well said. I work on the Ramda (http://ramdajs.com/) FP JS library with the OP. Ramda is heavily invested in currying, and I don't yet have a clue how we'll deal with default parameters. At first guess, we'll simply have to explain that we can't curry such functions. Such a shame!


I think the concern is simple, really.

People are going to be told (rightly so) to use `let` instead of `var`. If they do so too mechanically, and their code is structured in certain ways, an expression which could never before throw an exception in Javascript, `typeof x`, now will do so.

This is not the end of the world, by any means. And it doesn't add an exception into unchanged code, but it still is a legitimate concern.


In pretty much every case, if changing 'var' to 'let' would trigger this issue, the original code isn't doing what the author thought it was.


Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: