
Haskell in ES6: Part 1 - megalodon
http://casualjavascript.com/javascript/es6/haskell/native/implementation/2015/11/12/haskell-in-es6-part-1.html
======
pdpi
I'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.

~~~
sdegutis
> 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
In 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
Well, 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
The 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
Yeah 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
Unfortunately 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

~~~
tlarkworthy
I 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)));
      }

------
icholy
Haskell's strengths are it's laziness, currying, and type stystem.
Implementing a few higher order functions != haskell. This is HN clickbait.

~~~
chowes
I 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.

------
olalonde
Pretty 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
> 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
For some reason, the original author decided the arguments themselves were the
"list" to operate on which is indeed a bit weird and non idiomatic.

------
sjclemmy
I 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!

------
kmonad
May 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.

------
nvartolomei
Why `Array.prototype.slice.call(xs, 1)` for tail operation?

~~~
exogen
The 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]`.

------
bricss
Please, keep bloging

------
amelius
But how to implement laziness?

~~~
tel
Non-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
So, 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;
        }}
      }

------
mbrock
Here'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)

~~~
alextgordon
> A lot of my friends are starting to have children now, and they're all
> trying not to use words like "fuck" and "shit" within baby's hearing, lest
> baby start using these words too. But these words are part of the language,
> and adults use them all the time. So parents are giving their kids an
> inaccurate idea of the language by not using them.

"Wankery" is a great word! It's fun to say, fun to read. It is a criticism,
but with some humour to it. Isn't that what we should be encouraging?

Its only crime is vulgarity, but there is no HN guideline against that.

~~~
mbrock
I regret my comment.

