7 ms·
Haskell in ES6: Part 1
- bricss 11y agoPlease, keep bloging
- sjclemmy 11y agoI found the way the examples are written confusing at first glance. I think the norm is to call the function and then show the returned output. e.g. instead of 1/4 === comp(1) do comp(1) // returns 1/4 This might be my personal preference but it's the way it's written in the Mozilla javascript reference pages. Other than that it looks great!
- nvartolomei 11y agoWhy `Array.prototype.slice.call(xs, 1)` for tail operation?
- deleted 11y ago[deleted]
- exogen 11y agoThe code was probably converted from using `arguments` (which needs `Array.prototype.slice`) to using `...rest` params, and they just overlooked updating this line. The line above it also has a bug: it should be `xs.slice(-1)[0]`.
- kmonad 11y agoMay I ask what the (ideal) outcome of this would be? I'm not sure this is clear to me and I couldn't find more info on your blog.
- olalonde 11y agoPretty cool. Few suggestions (which may or may not require babel): - `f.apply(null, args)` calls can be replaced with `f(...args)` - Your head function returns the first argument while your last function returns an array containing the last argument. I'd rewrite those functions as: const head = (x) => x; const last = (...xs) => xs[xs.length-1]; const tail = (x, ...xs) => xs; const init = (...xs) => xs.slice(0, -1); (Unfortunately it seems the rest operator can only appear as the last argument.) - Why put everything on the prototype? It doesn't seem necessary since you are not using the `this` keyword. I would just stick the `export` keyword in front of functions to be exported. Looking forward to part 2.
- nunull 11y ago> head extracts the first element of a list, which must be non-empty. Those functions operate on lists. I think it should read as follows. const head = (xs) => xs[0]; const last = (xs) => xs[xs.length-1]; const tail = (xs) => xs.slice(1); const init = (xs) => xs.slice(0, -1); Am I missing something?
- olalonde 11y agoFor some reason, the original author decided the arguments themselves were the "list" to operate on which is indeed a bit weird and non idiomatic.
- heydenberk 11y agoYou can also avoid reversing the arrays before reducing them by calling the method `reduceRight`.
- amelius 11y agoBut how to implement laziness?
- homarp 11y agodon't do it yet.
- tel 11y agoNon-strictness can be implemented with functions. function thunk(f) { return { force: f } } This, for instance, gives you a lazy stream function unfold(step, state) { return thunk(function () { let m = step(state); if (!m.ok) { return {}; } else { return { head: m.value, tail: unfold(step, m.state) }; } }); }
- hawkice 11y agoSo, thunks should avoid multiple evaluation, too, and handle exceptions in a way that is relatively coherent. I like: function thunk(f) { var evaluated = false; var value = undefined; var excepting = undefined; return { force: function () { if (!evaluated) { evaluated = true; try { value = f(); } catch (e) { excepting = e; } } if (excepting) throw excepting; return value; }} }
- pdpi 11y agoI'm not quite sure what the end-game is, here? Several of the functions listed here are quite different from their Haskell counterparts in ways that make them subtly less useful — and in ways that make them not have the same types as the Haskell originals, which is interesting considering we're barely given more than the type of each of the functions. flip and zipWith are the ones that were quite obvious to me, others might have the same problems (with flip being outright wrong due to it inverting all the arguments instead of flipping the first two, and zipWith working fine with two lists, but generalising to multiple lists in a way that can't be a generalisation of the two-list zipWith). Composition also works in reverse to what one would expect in Haskell, for no reason I can fathom.
- deleted 11y ago[deleted]
- davidguerrerom 11y agojnjkblbkb
- sdegutis 11y ago> I'm not quite sure what the end-game is, here? My guess is that it's to show that (1) Haskell is pretty awesome, and (2) EC6 is pretty awesome too. In reverse order maybe?
- pdpi 11y agoIn my mind it doesn't achieve either. Functional programming isn't an end unto itself, it's one of several strategies for breaking programs down into manageable chunks. Without showing how this type of tiny function is used in journeyman Haskell code, nor showing how the translation to ES6 would apply to real world JavaScript, it just feels like functional wankery.
- sdegutis 11y agoWell, I agree that code for the sake of code is dumb. But I can also imagine practical applications for these things. So, it gets a +1 from me.
- infinity0 11y agoThe biggest power of Haskell (and other functional programming languages) is in the type system and the ability to abstract well (e.g. equals()), and these functional functions are secondary. How do you suppose to replicate that in JS?
- tlarkworthy 11y agoYeah it seems it would be much more useful with TypeScript as the substrate given its structural typing features. e.g. Declare interfaces that do the type class stuff, then any object that meets the interface critera can be used in those methods, without ever having to nominate the object as implementing the said interface. You have have parameterized interfaces too, so the functions can be pretty flexible.
- spion 11y agoUnfortunately TypeScript doesn't support higher kinded types, so you can't write interfaces for most of Haskell's most popular typeclasses. And there is something that a dynamic (and/or gradually typed) languages will never be able to do: function overload based on the function's return type, e.g. like Haskell's `return` :) edit: oh wait, after monad of no return its `pure` :D
- nbouscal 11y agoEven if MRP goes through, it'll almost certainly still be `return` for most people for a very long time. It just won't be part of the typeclass :)
- tlarkworthy 11y agoI was pleasantly surprised how far the type system goes though. Thanks to structural typing I get the pipe operator even for things I do not declare as SignalTransformers in the following: interface SignalFn<T> { (time: number): T; } interface SignalTransformer<A, B>{ (a: SignalFn<A>): SignalFn<B> } // the >>> function function pipe<A,B,C> (a: SignalTransformer<A,B>, b: SignalTransformer<B,C>): SignalTransformer<A,C> { return (x: SignalFn<A>) => b(a(x)) } // the arr lift function lift<A, B>(fn: Function1<A,B>): SignalTransformer<A,B> { return (input: SignalFn<A>) => <SignalFn<B>>((time: Time) => fn(input(time))); }
- mbrock 11y agoHere's another way of phrasing that. "Functional programming isn't an end unto itself, it's one of several strategies for breaking programs down into manageable chunks. I would have found the article more interesting if it showed how this type of tiny function is used in journeyman Haskell code, or how the translation to ES6 would apply to real world JavaScript." http://blog.ycombinator.com/new-hacker-news-guideline http://blog.ycombinator.com/new-hacker-news-guideline
- verbin217 11y agoYou can fuck right off. I found the last part useful. It's exactly what it was and why I found it annoying. Wankery means something in addition to being distasteful. This is it. Sorry if you were offended.
- deleted 11y ago[deleted]
- verbin217 11y agoActually no. It demonstrates it directly. Can you not still parse the information? Honestly there's a point where an army of politeness enforcing assholes becomes its own form of intolerance. Just shut the fuck up now please before we dump more useless shit in this thread.
- deleted 11y ago[deleted]
- deleted 11y ago[deleted]
- dang 11y ago> You can fuck right off > Just shut the fuck up now Comments like this break the HN guidelines. We ban accounts that do this, so please read and follow them from now on. I don't disagree with your point about the comments upthread, and perhaps you were being extremely rude as a rhetorical device, but please don't—it does more harm than good. https://news.ycombinator.com/newsguidelines.html https://news.ycombinator.com/newsguidelines.html https://news.ycombinator.com/newswelcome.html https://news.ycombinator.com/newswelcome.html
- icholy 11y agoHaskell's strengths are it's laziness, currying, and type stystem. Implementing a few higher order functions != haskell. This is HN clickbait.
- chowes 11y agoI don't think the author's goal is to recreate Haskell in Javascript. There's appeal for JS devs like myself to learn / use Haskell paradigms like those you've mentioned in their codebases without having to learn a whole new language.