11 ms·
Trine – A utility library for functional programming in JavaScript
- amelius 11y agoWhat Javascript needs is a way to deterministically (re)run it, so that errors can be traced.
- jpeterson 11y agoWhat's stopping you from doing that, exactly?
- monk_e_boy 11y agoHe's probably having issues with async gubbins. Some sort of 'rewind time' in the debugger so you could determine what happened when to get to this state of error.
- amelius 11y agoI also want to be able to run javascript (and the rest of the browser) deterministically in a test environment, and run tests, each with different timing characteristics. Of course, I want to run my server in the same way. So perhaps this is better done inside some "deterministic virtual machine", where the browser and server are run deterministically hand-in-hand.
- jpeterson 11y agoFirst of all, the browser environment is the asynchronous part here, not JavaScript. JavaScript is a language that happens to be interpreted on top of that environment. You'd run into similar issues with any other language over an asynchronous execution model. Second, you can actually execute browser and node code deterministically if you like, by providing alternative implementations of setTimeout, setInterval, setImmediate, etc. that serialize execution of the callbacks in the order of your choice.
- judemelancon 11y agoThe best vendor-neutral term for rewinding time in a debugger is probably "historical debugging" or "reverse debugging".
- braythwayt 11y agoLooks interesting, especially in concert with the proposed bind syntax. Fortunately, that syntax is in Babel now, so we can play with these ideas straight away. That being said, the readme did not address why Ramda uses the data as the last parameter and not as `this`: To facilitate partial application.
- quinnirill 11y agoRamda actually uses data as the last parameter usually, whereas lodash has it as the first. However, I agree, the readme doesn't quite show the full power of Trine. Trine has `partial`, which allows you to do partial application as so: `parseInt::partial(_)`, that would create a function that acts as parseInt but only takes one argument. This is in sync with the partial application syntax proposal: https://gist.github.com/anonymous/5c4f6ea07ad3017d61be https://gist.github.com/anonymous/5c4f6ea07ad3017d61be The rest of the functional goodness, such as autocurrying are still undecided upon because in my personal experience autocurrying in JS is awkward and leads to bugs that are hard to debug. I'm also considering compose and a combination of compose and partial (e.g. apply a function to a parameter at a certain place), but again subjectively, composing functions like that has reduced the readability of codebases. JS already has first class functions which allows composition pretty easily, the only problem is that it's overtly verbose - I'm still hoping to see the single arrow function land in JS some day. :)
- notNow 11y agoMay I ask what do you mean by "single arrow function"? Do you mean thin arrow fn(s)?
- quinnirill 11y agoYes, sorry, thin arrow, not single - `() -> this.foo()` for function expressions and possibly even `let/const fn () -> this.foo()` for declarations.
- notNow 11y ago
- loganfsmyth 11y agoLooks cool. Not sure I get why installing `babel-runtime` would be something you'd have as a separate install step though, since there is no guarantee that the user would install the right version.
- quinnirill 11y agoThis is to avoid multiple versions of Trine required by libraries (or the application itself requiring a different version of babel-runtime) causing the different versions of `babel-runtime` to be included multiple times, which would be a problem especially for browser applications. Trine itself is very small, but if each module introduces a dependency to babel-runtime, it would be another case of "npm downloads the whole internet". :/
- loganfsmyth 11y agoTo me at least, that's more up to NPM to manage though. As it is, it means you're essentially sidestepping npm. There's also no guarantee that people will install a version of babel-runtime that is compatible with the version of Babel that you used to publish the code. It also means trine can never upgrade the version of Babel it is using internally, since Babel could change the helper name that it uses or something, but that might not exist in the version of babel-runtime being used in the code that depends on trine.
- secoif 11y agoOne downside of passing data as `this` that isn't mentioned is you can't use the concise function syntax `=>`. If we ever get thin arrows this problem will go away.
- quinnirill 11y agoRight on the point. I'm still hoping for that to get in at some point. :)
- inglor 11y agoThere's no point of using `=>` arrows if you're using the bind syntax they're mutually exclusive.
- milkworsethan 11y agoYou could always use FP languages for FP and leave JS be...
- gabipurcaru 11y agoWell you can't really. If you want to write frontend apps, for example, you have to use JS. You could technically use some FPLang-to-JS compiler, but those suck more often than not. Also, I don't see how "let's not make a thing better just because it was not meant to work this way" is an argument. I'm sure there is a fallacy name for this, but consider some other examples: "You could always use fridges for cooling and let cars be" or "You could always use computers for browsing the internet and leave phones be".
- Arcanum-XIII 11y agoI'm using on my day to day ClojureScript and have, till now, 0 technical issue. Is this the perfect platform ? Hell no, it can be annoying to set, and interop can be annoying (mostly due to the fact that the world of side effect is still there, lurking and come at odds to my immutable language). The upside is that it works. For me it's a relief to use a FP compare to OO, some would prefer a logic (prolog) approach, or else - and again, we can, right now and it's no harder than using grunt, bower or any of the other tool that have appeared recently.
- fnordsensei 11y agoYou could technically use some FPLang-to-JS compiler, but those suck more often than not. Some citation needed on that one. I've got a whole host of contradictory examples. Do you mean to say that you personally have not fancied any of them so far? If someone has done some deeper digging into the state of compiled vs. handwritten JS I'd be delighted to read about it though.
- deleted 11y ago[deleted]
- mattdesl 11y ago> You could technically use some FPLang-to-JS compiler, but those suck more often than not. Features like the function bind syntax are only possible with Babel or another transpiler. It will likely be years before you can use them practically without a transpiler in the browser. A lot of the new syntax/macros/APIs/etc should just be built as modules or Babel plugins rather than core language features. Just because [Syntax X] improves a couple of code snippets doesn't mean it needs to be shipped with the next version of JavaScript.
- agumonkey 11y agoI recall lodash author saying that if you want HOF, Datum order to change you can `rearg` the whole library to suit your needs. Maybe the performance penalty is too large, I never tried it.
- romanovcode 11y agoLooks like some kind of LINQ implementation for JS.
- innguest 11y agoAlso known as the List monad.
- bshimmin 11y agoAbout halfway through the README, after some examples of the new bind syntax, it says "But why stop there?" Actually, please can we stop here? Just for a bit? This continual, persistent mangling of JavaScript's syntax really is starting to hurt. It's one thing to have to keep on top of the new frameworks springing up every five minutes - which you can, for the most part, ignore for at least six months until they start to gain some traction or have disappeared entirely - but when the core language itself is changing (and growing) at this rate, it really becomes an altogether more disconcerting and nightmarish proposition.
- delluminatus 11y agoI disagree. I think that extending and improving a language is good, and it's certainly not a Javascript-only phenomenon. Off the top of my head, other languages that are considering and implementing syntax extensions include Python (e.g. "yield from"), C# (e.g. "async/await"), and Java (lambda expressions). I actually think that it's pretty low to accuse ECMAScript of "mangling" JS syntax when they are just trying to add modern extensions that make common patterns easier. Of course this function bind syntax is just a proposal and hasn't been accepted into the standard yet. But what about it bothers you so much? What about iterators or shorter function definitions, are those also nightmarish manglings of syntax? I mean, really. The usage of Javascript is evolving from simple embedded scripts to gigantic client/server applications. It's no surprise that the language itself will evolve as well.
- colin_jack 11y agoYou have a point but you mention C#, it's worth thinking of how you'd handle one of the examples in C#: items .filter(isOk) .map(toOtherType) ::flatten() In C# that sort of case is primarily handled by extension methods. They have their issues not least in terms of collisions, but to me they are a beautiful solution. The equivalent in JS would seem to be the always unpopular choice of adding these methods to the prototype, and as with extension methods you'd want the user to opt-in to their addition (possibly at object level here?). Not sure though, maybe I've missed something.
- thomasfoster96 11y agoPerhaps what programmers of modern JavaScript should be doing is going back and revisiting things that have been considered harmful practices for quite a while. Some work in extending prototypes would make a huge difference to the readability of lots of code - yet everyone is told this is a bad practice because extending DOM elements is problematic and people are lazy when it comes to global namespace pollution. Realistically, neither of those are reasons for it to be bad practice anymore.
- TazeTSchnitzel 11y agoExtending prototypes seems like a great idea, until other code running in the same environment does it, and you realise why people stopped doing that.
- cowardlydragon 11y ago?Namespaces?
- quinnirill 11y agoAnd also because it has prevented the language itself from standardizing some features, e.g. String.prototype.contains had to be renamed to includes because shipping it as contains would have broken sites that use mootools.
- brunoc 11y agoFor those of you like me who spat their coffee reading this, you can find additional information about this anecdote here. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/includes https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
- deleted 11y ago[deleted]
- TazeTSchnitzel 11y ago
- coldcode 11y agoIt's a shame there isn't any cross platform supported alternative to mangling javascript even further. But getting all browser developers to agree is probably an even worse nightmare.
- the_mitsuhiko 11y ago> They're both (subjectively) wrong: the natural place for data in JS is the this parameter. ... said the person not understanding the language semantics. Passing arbitrary data as this is a terrible idea. It has to be an object and as such all primitives end up boxed.
- inglor 11y agoNot in strict mode... `(function(){ console.log(typeof this); })(5);` try in sloppy and strict mode - remember modules are strict mode by default.
- codecurve 11y ago(function double() { return this * 2; }).call(2) === 4 I didn't have to box anything to pass a primitive as this. Maybe some other versions are different, but this works in Chrome 40 and Firefox 33.
- implicit 11y agoAre you sure? > function isboxed() { return this instanceof Number; } > isboxed.call(5); true
- CrossEye 11y agoas inglor said, this depends on strict mode: > var isboxed = (function() {"use strict"; return function isboxed() {return this instanceof Number;}}()); > isboxed.call(5); false
- tracker1 11y agoThis, and eval are probably the two largest points of JS where unintended mutations and consequences happen. Also, by overloading this (which is something I always hated in jQuery), you lose the ability to compose functions together, and/or use other types of currying and binding for event handling and/or processing. IMHO it's usually something to be avoided, not championed...
- deleted 11y ago[deleted]
- Kiro 11y agoWhat's up with the snarky slogan?
- venomsnake 11y agoI hope that the authors have cleared the name with FrozenByte studios ...
- SwellJoe 11y agoTrademark doesn't work the way you think it does. Just as no one is suggesting Rust the game and Rust the programming language are violating each others mark...this Trine doesn't violate other "Trine" marks. Trademark is protection for a specific mark in a specific industry, and not the exclusive right to use a word for any purpose. Made up words are sometimes more strongly defensible... Thus "Google" would not be usable legally in the US for any product. But "googol" might be for products that don't overlap with products made by Google. But, Trine is not a made up word.
- dimgl 11y ago> The library modern JavaScript doesn't deserve, but needs right now. Fucking lol, why?
- CrossEye 11y ago(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?
- yanis_t 11y agoAgreed. And btw thank you for Ramda, which is a very beautiful thing. Too sad in day-to-day web development lodash is just enough.
- CrossEye 11y agoThat'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.
- jgord 11y agoand thanks again for Ramda .. I use it daily for real work, back and front end.
- smrtinsert 11y agoIf you mean using frameworks to display data, then yes. For anything substantial I'd use ramda over lodash.
- jdd 11y agoWhy 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 https://www.npmjs.com/package/lodash-fp
- rikrassen 11y agoIt seems to me like everybody wants a framework in every language that allows them to write it like a language they're more comfortable with. I would much prefer to see the evolution of FFIs, and things like that, than just writing a DSL that's more or less just sugar. Let's embrace the native strengths of languages, and allow ourselves to use more languages together.
- nateabele 11y agoGosh, and here I thought functional programming was about composing higher-order functions independent of the data on which they operate. I guess the Lodash/Underscore definition of "functional" was right after all! </sarc> ...I'ma go back to using Ramda now.
- hajile 11y agoWTF!! One of your iterator example for primes uses GOTO (aka labels). It may be different where you work, but anyone in my company using labels either has the mother of all excuses or is going to be a warning away from termination.
- quinnirill 11y agoSounds like a very healthy company culture. ;)