Hacker News new | ask | show | jobs
by boothead 3896 days ago
If you're an analytics shop (presumably) working with streams of events, I'm going to go out on a limb and say that not picking a functional language (purescript or elm) is a mistake. It's fits the domain so well, take a look at the mileage that slamdata are getting out of purescript for example.

note I'm being deliberately provocative with the above statement to promote discussion, not argument. :-)

5 comments

I don't think it makes that much sense w.r.t stream events:

1. most of the analytics/event-stream processing will be done on the backend anyway

2. If you are picky enough you can do functional programming in js. Reative.js is decent library for processing streams of events.

What screams to use something more haskell-like, is their example of 'Trys', i.e:

  class GraphQuery extends Query {
    static parse(object: any): Try<GraphQuery> {
      return TimeRange.parse(object.over).flatMap((timeRange: TimeRange) => {
        return Filter.parse(object.where).flatMap((filter: Option<Filter>) => {
          return GroupBy.parse(object.by).flatMap((groupBy: Option<GroupBy>) => {
            return new Success(new GraphQuery(
              filter,
              groupBy,
              timeRange
            ));
          });
        });
      });
    }
  }
should look like something like:

  parse : Any -> Try GraphQuery
  parse object = do 
    timeRange <- TimeRange.parse object.over
    filter    <- Filter.parse object.where
    groupBy   <- GroupBy.parse object.by
    return (createGraphQuery filter groupBy timeRange)
(haven't used haskell in quite some time, so maybe I am missing something)
>should look like something like:

    >   parse : Any -> Try GraphQuery
    >   parse object = do 
    >     timeRange <- TimeRange.parse object.over
    >     filter    <- Filter.parse object.where
    >     groupBy   <- GroupBy.parse object.by
    >     return (createGraphQuery filter groupBy timeRange)
New ECMAScript 2015 Style

    parse = ({by, over, where}) => {
      timeRange = TimeRange.parse(over)
      filter    = Filter.parse(where)
      groupBy   = GroupBy.parse(by)
      return createGraphQuery(filter, groupBy, timeRange)
    }
or

    parse = ({by, over, where}) => 
      createGraphQuery(
        Filter.parse(where),
        GroupBy.parse(by),
        TimeRange.parse(over));
or

    parse = ({by, over, where}) => 
      createGraphQuery(
        Filter(where),
        GroupBy(by),
        TimeRange(over));
or

    parse = ({by, over, where}) => createGraphQuery( Filter(where), GroupBy(by), TimeRange(over) );
or

    parse = ({by, over, where}) => c(f(where), g(by), t(over));
and, if you're willing to put a front-end on it:

    parse = ({b, o, w}) => c(f(w), g(b), t(o));

Of course, I have not provided the definitions of `c`, `f`, `g`, or `t`.
This is slightly different from the original code. The reason for all the flatmapping is to avoid continuation if any of the subparsers fail, and notify the caller that something has failed because of {some exception}.

You can avoid excessive nesting/flatmapping with some syntax sugar, but it needs to be sufficiently different from normal declarative code.

I alluded to that in my last note. :)

If you properly define the functions (`c`, `f`, `g`, `t`), you can get the semantics of halted computation on failure. That is essentially what Haskell's `do` notation does.

You're absolutely right! I was hoping someone would point this out, since this is a much cleaner way of writing this code. This is pretty close to how it's done in Scala.

For the purposes of this article, we tried to avoid too much syntax sugar to make it more accessible. That aside, I'd love to add something like this to monapt![1].

[1] https://github.com/jiaweihli/monapt

Here’s a sketch of some potential syntax to simplify your TypeScript so it’s like that Haskell code.

  class GraphQuery extends Query {
    static parse(object: any): Try<GraphQuery> {
      return TimeRange.parse(object.over)
        .combinedWith(() => Filter.parse(object.where) )
        .combinedWith(() => GroupBy.parse(object.by) )
        .withCombinedValues((timeRange, filter, groupBy) => {
          return new Success(new GraphQuery(filter, groupBy, timeRange));
        });
    }
  }
In this design, `combinedWith` is a lot like `then` when using promises. It’s a bit more complicated because `then` assumes that arguments are always passed directly from the previous function, so you need special support to store the return value and retrieve them later as arguments.

If the type system requires it for some reason, you could add a `.startCombining()` call at the end of the first line within the method, so that `combinedWith` is sure to be possible.

You can build UIs as a left fold over events, just as you can build backend data processing pipelines. In fact it that is the architecture that makes the most sense to me now. I have a little toy framework here that demos these ideas. https://github.com/boothead/oHm
May be you can funscript? http://funscript.info/ It leverages TypeScript metadata to do typed interop with JavaScript libraries through an F# type provider
I know zero developers who know purescript or elm. That is a hiring problem, especially for young companies.
I know a few Elm developers. Using a less mainstream language can actually be a boon to hiring. (Isn’t there a classic PG essay on how ViaWeb benefitted enormously from using a Lisp when no competitors did?)

> Had our first hire start today who applied because we use @elmlang in production. He rocked it!

> PS: still hiring :)

https://twitter.com/rtfeldman/status/656238188961226752

Furthermore, I’ve learned so many languages on the job in my career that I am unsympathetic to companies who refuse to believe that people who have learned programming can continue to learn programming!

PG has a couple essays directly related to this topic. The first about using a language which is implicitly more powerful than others ("Beating the Averages") [1] and the other is about how using a less common language is a positive selector in the hiring process ("The Python Paradox") [2].

[1]: http://www.paulgraham.com/avg.html [2]: http://www.paulgraham.com/pypar.html

Agree on the first. On the second, "And people don't learn Python because it will get them a job; they learn it because they genuinely like to program and aren't satisfied with the languages they already know.". I disagree, I like to solve problems more in Java. I tried several including Python over the years. I'm asked to do something in Python I will but for my money, Java is more readable than Python. It's an acute and false observation that he made. Less common does not necessarily equate to smarter/better/faster.
This was dramatically more true of Python when he wrote it than presently. FWIW, I've recently been using Python for a job and find it deeply unsatisfying. I'm inclined to think that current-gen Java may well be better; the last time I used Java in anger it was basically a different language. Though to be fair, truly modern Python is also a bit different than what I've been working in.
PG isn't God, and he related a single anecdote. I won't believe that argument unless I see current data that's language-specific.

For example, I could imagine easily being able to hire devs to work on Go, but it'd probably be really hard to get them to work on Haskell.

> PG isn't God

Can you prove that? Absence of evidence isn’t evidence of absence, after all. You’re being a bit militant in your pg-atheism.

Okay, in all seriousness, you are correct. Ability to hire coders to work in a particular language is a legitimate concern to have. Still, it’s sad to see lack of usage drive, well, lack of usage – sometimes it looks to me like an unexamined assumption, or a self-fulfilling prophecy. To take it back to the land of religious arguments: it’s a bit cargo-culty.

I agree with what you're saying, but "low popularity" is just one mark on one side of the pros/cons list.

New languages can outweigh low popularity with lots of other important qualities: syntax, tooling, appropriateness for a certain purpose, abundance of libraries, etc. If the new language is easy to learn, that pretty much defeats the issue of low popularity all together!

Unfortunately, a lot of new/amazing languages with great tooling are somewhat hard to learn. Again, Haskell might be a great language, but it's daunting to people who only have experience with C-like languages.

Go is one of the exceptions, and I think it did that intentionally. Instead of having complex syntax, it just has lots of boilerplate. It's easier to read and easier to learn at the expense of being harder to write and harder to modify.

> New languages can outweigh low popularity with lots of other important qualities [...] abundance of libraries, etc.

How?

> If the new language is easy to learn, that pretty much defeats the issue of low popularity all together!

If the language is easy to learn it's probably not worth learning. "Easy to learn" in most contexts and for most people means "similar" or "familiar".

Of course, there are languages truly easy to learn thanks to their small surface and internal consistency (like Erlang, PicoLisp, Forth...) but they are very rarely regarded as such.

> Again, Haskell might be a great language, but it's daunting to people who only have experience with C-like languages.

My opinion is that it's their problem, not Haskell's. Instead of "being daunted" they should go polyglot already and stop whining.

> [..] but it'd probably be really hard to get them to work on Haskell.

I've been on both sides of Haskell hiring. There's more people who want nice Haskell jobs than Haskell jobs advertised these days.

Any recommendation on a good place to post Haskell jobs?
> That is a hiring problem

On the one hand there's a smaller pool of people, on the other hand a primary issue in hiring is sifting people who can do the job from a random draw[0], in which case interest and/or knowledge of Elm or Purescript is a huge prefilter, and can draw/poach people who wouldn't otherwise be interested (pg's "the python paradox"[1] talks about that)

[0] or worse, you don't get a random section of developers, you get a section of developers currently looking for a job, so the average competence of your draft is below average.

[1] http://www.paulgraham.com/pypar.html

Try ClojureScript.

There are plenty of developers, especially here on HN, who would absolutely love to work with Clojure/ClojureScript full-time.

I desperately want to extend my exposure to Clojure/Clojurescript. Unfortunately I can't use in my current company. I'm trying to play with it in my own time, which is of course very scarce. I wish more companies realized how amazing Clojurescript is.
A while ago, I had occasion to look for Haskell programmers, to hand off a project to. Despite promising to offer substantially below market rate, with no chance of a major pay-day, I got quite a pile of seemingly serious applicants for the position, some quite impressive. While the project had some non-profit volunteering good vibes around it, I think the experience is still worth noting for those interested in the ease of recruiting developers of niche languages.
Then hire someone who knows Coffee or Type and teach them Purescript? Its not that hard for developers to pick up a new syntax if they understand the framework and ecosystem around it...
Calling PureScript "new syntax" is a huge understatement.

I love PureScript (and Haskell, FWIW), but it's a huge paradigm shift from CS, TS, or JS.

It's counter intuitive but picking one of these niche technologies means:

1) you'll need less people (better more reusable code) 2) the best people will speak you out.

This was very much my experience when I put a Haskell team together, and everyone I've spoken to who has done the same has said the same.

It's an opportunity for a young company, not a problem.

I don't know purescript or elm, so I can't speak for their qualities. But, I also don't know half the languages cited nearby either (livescript, clojurescript). How can I pick and learn "the right one"? They all seem the same to me, and I think that's the problem.
Would make more sense to use a FRP library like Rx.js . Introducing yet another language+pipeline just for that is questionable.
Agreed, and a good middle-ground between JS and purescript/elm is livescript: http://livescript.net/blog/functional-programming-in-javascr...
> not picking a functional language

As opposed to what? In what ways do you not consider Javascript to a be a functional language?

Sure, Javascript has first class functions, which I guess meets the bare minimum requirements for being a functional language, but it also lacks some key features:

* Pure functions - JS functions are essentially subroutines. They might return a useful value or they might mutate a bunch of stuff and interact with the outside world. Who knows? JS functions aren't guarunteed to return the same value, or any value at all.

* Immutability - Anything and everything can be mutated in JS, including the contents of objects that are defined using the new ES6 `const` keyword

* Curried functions by default - Although it's possible to compose or partially apply JS functions, it's not nearly as nice as Haskell or Elm.

You're influenced by only one part of FP world. Let's take Lisp, or even better: Scheme.

   * pure functions - all you said is equally true for Scheme
   * immutability - set-cdr! and many SRFIs: vectors, boxes, records...
   * curried by default - nope, not in Scheme either
There are other flavours of FP languages other than ML descendants. They are not "less functional" at all.
It's true, not every language goes all-in on functional programming — but just because some functional languages are less strongly functional than others, that doesn't mean it makes sense to call every language currently in use a functional language.

I mean, it seems pretty useless to define "functional programming language" in a way that includes both C and OCaml just because you can pass functions around in both of them.

   var a = 1;
   a = 2;

   window.someGlobal = 'foo';

    const a = {b: "foo"};
    a.b = "bar";
Yea, const provides immutability with respect to assignment, but without immutable objects and collections, it isn't going to get you all the way.

    const a = icepick.freeze({b: "foo"});
Granted, that's not as elegant as built-in support but that is literally what I'm doing at the moment when I want immutability.
So if you go to extraordinary lengths you can use JavaScript functionally but it's not very functional by default aside from the first-class functions. Personally I just embrace it's imperative/functional blended nature and go with it.
Microsoft ruined C# by adding var. var is not your friend. Dynamic typing is not your friend and static languages pretending to be dynamic is akin to evil.
Implicit typing is not dynamic typing, or even "pretending to be dynamic". It's also, I think, off topic - as the example seemed to be talking about mutability in JS, with no C# for miles.
A functional language can allow mutations (see Haskell, LISP, etc.).

All a functional language really needs is first class functions. JS has had that since the very beginning.