Live data from Hacker News

Why GitHub used Haskell for Semantic

github.com

171–180 of 214 posts

Re: Why GitHub used Haskell for Semantic

#171
post #88

Earlier quoted context omitted.

> I agree. You master monads and IO, but then you want to use a web framework and there a bunch of other category theoretical concepts and/or Haskell advanced features you need to understand to serve up "Hello World". Compare that to expressjs. I started using haskell at my last job after having done a couple years of functional programming in scala, but I honestly never found it required that much knowledge of categ…

+1 everything you said. Do you think it would be dramatically improved if Haskell had a bigger community of people contributing user-friendly libraries and tutorials? That was something that made Ruby the perfect newbie language for me. And something I feel is downplayed in Haskell given it's more advanced user base who is a little too obsessed with it's power and demonstrating their knowledge as such, rather than he…

> Do you think it would be dramatically improved if Haskell had a bigger community of people contributing user-friendly libraries and tutorials? That was something that made Ruby the perfect newbie language for me. And something I feel is downplayed in Haskell given it's more advanced user base who is a little too obsessed with it's power and demonstrating their knowledge as such, rather than help make it accessible to others.

Absolutely. I think it's been getting better at that on the tutorial front. For a long time there were very few books I'd actually recommend for haskell, but Haskell Programming from First Principles [1] changed that for me (personally). And I think Stephen Diehl's excellent What I Wish I Knew When Learning Haskell [2] is a fantastic general resource for newbies. But I think the community could stand to have more of this, absolutely.

And I definitely agree about libraries. I'd like to see more haskell libraries with extended tutorials, and written w/ a non-expert audience in mind. I think the community has for so long been dominated by long-time haskell developers and people ensconced in functional programming, much of the documentation is written for those kinds of people.

[1]: http://haskellbook.com/

[2]: http://dev.stephendiehl.com/hask/

Re: Why GitHub used Haskell for Semantic

#172
post #12

Earlier quoted context omitted.

I havr never noticed immutable data structures to be more difficult to deal with. For the most part, because of monads and effects and such you can essentially write better imperative code in haskell. Im noy sure why youve decided that haskell is incapable of the syntactic appearance of mutation.

To be fair I haven't really used it, only read the core of the guide, so I may be mistaken. But I've done a bit of Clojure, and I've done a bit of Immutable.js, and particularly when you have a deeply-structured piece of data, "mutating" something a few levels down gets really ugly. Now, maybe something about Haskell Enlightenment obviates this case entirely in a way I'm not seeing. But I also remember Haskell seemin…

Haskell obviates the need to do deep manipulations in an ad hoc 'ugly' way usually via lenses. Personally, i think most imperative languages are sufficiently less sophisticated than a state monad plus lens thay it is substantially more difficult to use them.

> But I also remember Haskell seemingly forcing you to push all your imperative code up to the surface layer of your otherwise pure program

I have no idea what you're talking about. You seem to be confusing effectful code with imperative code. Haskell's do notation -- which lets you write with an imperative syntax -- can appear anywhere, including pure code. On its own imperative code does not necessarily mean effectful code and mutation does not require us to give up on purity. Moreover, if you do want machine level mutation for performance reasons or because an algorithm is more easily expressed in that way, you can always drop into the (again pure) ST monad.

Basically, I think you are criticizing haskell from a place of ignorance.

Frameworks like immutable.js are not comparable to haskell. These are immutable data structure libraries built for languages where immutable data is an afterthought at best, if its even considered at all. Obviously these are going to be clunkier to use. Haskell is not that though.

Re: Why GitHub used Haskell for Semantic

#173
post #32

> An example of this is the concept of resumable exceptions. During Semantic's interpretation passes, invalid code (unbound variables, type errors, infinite recursion) is recognized and handled based on the pass's calling context. ... Porting this to Java would require tremendous abuse of the try/catch/finally mechanism, as Java provides no way to separate control flow's policy and mechanism. And given Go's lack of e…

> > During Semantic's interpretation passes, invalid code (unbound variables, type errors, infinite recursion) is recognized and handled based on the pass's calling context. … And given Go's lack of exceptions, such a feature would be entirely impossible.

Nonsense! It’s completely possible — you just have to be willing to abuse a few of Go’s features in order to do it.

First off, Go does have a standard calling-context (i.e. dynamic context) mechanism: context.Context[0]. All you need to do in order to track stuff in the calling context is stash an object in the … context.

Given this dynamic context mechanism, you next need a way to represent handlers. That’s easy: a handler is a function which takes an exceptional condition and either handles it or returns; handling consists of a transfer of control. Fortunately, Go has a control-transfer primitive as well: panic. So to handle a condition, a handler just panics — something higher up the call stack can use defer to catch the panic and continue execution.

That leads to the next component necessary: a way to provide resumption points, or restarts. A restart is just a function which is invoked by a handler, potentially with arguments, and which when invoked continues execution from its establishment point. This can be done with defer.

So it’s perfectly possible with tremendous abuse of Go’s panic/defer mechanism, no different from Java.

See this gist: https://gist.github.com/r13l/2911f93cbe66fb4ed50f9d9eb1eb252...

Honestly, I don’t even know if I’d call it tremendous abuse, although it is somewhat abusive. Abstracted in a library, it might even be somewhat useful.

It’s off-the-cuff — I haven’t fully considered the semantics of the different context objects being passed around.

0: https://golang.org/pkg/context/

Re: Why GitHub used Haskell for Semantic

#174
post #149
post #88

Earlier quoted context omitted.

+1 everything you said. Do you think it would be dramatically improved if Haskell had a bigger community of people contributing user-friendly libraries and tutorials? That was something that made Ruby the perfect newbie language for me. And something I feel is downplayed in Haskell given it's more advanced user base who is a little too obsessed with it's power and demonstrating their knowledge as such, rather than he…

Ergonomics is probably the number one thing that matters on the long run for computer languages. Make the frequent things easy and safe. And this means syntax should be easy to read and write, documentation should be plentiful and easy to read, easy to start using, even if you are not expert in the area that that particular library covers, etc. Rust also suffers a bit from this, as more and more libraries are just th…

The more flexible a language is, the more documentation its libraries need.

One often-ignored benefit of constrained languages like Java where there's really only one way to do most things, is that when you get a library you immediately have a reasonable idea of how to use it (given the entity names and types). If a language has a more advanced type system (or none at all), you can't lean on that existing framework and the author needs to do more legwork to explicitly lay out exactly what it is they've made. This doesn't make more advanced languages bad, but library documentation is often neglected and that probably contributes a lot to the inaccessibility of those ecosystems.

Re: Why GitHub used Haskell for Semantic

#175

Earlier quoted context omitted.

If you'll forgive the analogy, Haskell is kind of like the Mercedes of production-ready research-grade languages. You may not actually use haskell, but the features that haskell is pioneering are what you'll see trickling down into other languages, as language designers look over and borrow things. Some examples (though they're not all invented by haskell, but haskell has popularized them IMO): - non-nullable types -…

> - abstract data types I suppose you meant to say "algebraic data types"? (which have been adopted by Rust and Swift, and even the C++ stdlib)

Yes definitely, I meant ADTs and GADTS -- Algebraic Data Types

They're a super good idea, so I'm glad that other languages are adopting it, but this is the kind of thing that haskell has had for a long time and is just second nature.

Re: Why GitHub used Haskell for Semantic

#176
post #122

Earlier quoted context omitted.

> When Rust started getting flooded with the "web" crowd of ex-Rubyists and the like there was a lot of push back from the traditional systems people (for better or worse). But one of the benefits is that these guys are typically far better at communicating and selling languages to the general developer public. I 100% agree -- this is the crowd that brings the hype (for better or for worse). I guess it's another one…

> Small shameless plug, No point plugging if you don't provide a link for us! :-)

I hear you! I was going to try and get the CountMin post done this weekend and update this but I guess I gotta let it roll with what I have already done:

One of my better Haskell posts is a series on writing REST APIs. It kind of gets off the rails type wise as I try to get more and more clever, but I rein it in:

https://vadosware.io/post/rest-ish-services-in-haskell-part-...

Re: Why GitHub used Haskell for Semantic

#177
post #32

> An example of this is the concept of resumable exceptions. During Semantic's interpretation passes, invalid code (unbound variables, type errors, infinite recursion) is recognized and handled based on the pass's calling context. ... Porting this to Java would require tremendous abuse of the try/catch/finally mechanism, as Java provides no way to separate control flow's policy and mechanism. And given Go's lack of e…

> One of the main reasons I don't care much about Haskell is because without any side-by-side comparisons of Haskell vs I don't understand what the Haskell advantages are, and I don't know when I'm dealing with a problem space where Haskell would help me. This is one of haskell's biggest problems. It's just enough outside of the normal flow of imperative languages (yet usable for the same problems) that you can't tel…

The selling point for me to get into Haskell was how much better it's lowest bar is than pretty much every other language I've used so far. It's not perfect but it has a very good effort to power ratio.

For example, I have a database with millions of unstructured, schemaless JSON documents. The documents are mostly similar but the schema is defined by Javascript code that has been maintained and modified for many, many years and so the documents have many, many edge-cases.

I've dared my team to write a JSON-Schema document that could validate our format. It would take a lot of effort to get that going. And it would be verbose and hard to work with: JSON-Schema itself is written in JSON and there exists no tool that can understand the types in the schema, validate them, etc until you run the program on some documents.

Instead I spent a few hours and wrote a type that loosely described some of the more common types I've come across in Haskell. I used the wonderful JSON libraries to parse documents from our database using my small, limited type in a test suite. It failed initially but the type system pointed out where it was failing and why. So I added more cases to my type, improved the parser, until I could parse a handful of real-world examples.

From there I wrote a tool that scans the whole database, collects the parse results, and displays the top N parse failures with example documents to add to my test suite. I use the test suite to interrogate the parse results, add more cases to my type, extend the parser, etc, etc...

I've spent very little time working on this and got my tool successfully parsing almost 90% of the database. When I add new examples the type checker guides me as I interrogate the new case, fix the edge cases, and get the tests to pass. Once I can parse 100% of this database I can start writing a tool to migrate my messy data structure into a more clean, consistent one with a more simple parser and prove that the migration is total. And I suspect it will take even less effort to do that.

I'm not even leveraging anything more advanced than ADTs, type classes, and functions. For very little effort Haskell has given me the ability to solve valuable problems. Problems that scared other developers away using other languages.

Re: Why GitHub used Haskell for Semantic

#178
post #12

Earlier quoted context omitted.

To be fair I haven't really used it, only read the core of the guide, so I may be mistaken. But I've done a bit of Clojure, and I've done a bit of Immutable.js, and particularly when you have a deeply-structured piece of data, "mutating" something a few levels down gets really ugly. Now, maybe something about Haskell Enlightenment obviates this case entirely in a way I'm not seeing. But I also remember Haskell seemin…

But I've done a bit of Clojure, and I've done a bit of Immutable.js, and particularly when you have a deeply-structured piece of data, "mutating" something a few levels down gets really ugly. As opposed to what languages?

  (assoc foo "bar"   
    (assoc (get foo "bar") "alice"   
      (assoc (get (get foo "bar") "alice") "bob" 12)))
vs

  foo.bar.alice.bob = 12;

Re: Why GitHub used Haskell for Semantic

#179
post #119

Earlier quoted context omitted.

> The most successful languages let you be pure-functional where it makes sense and then stateful where it makes sense. Haskell doesn't, really (from my cursory reading about it). This is absolutely wrong. Sorry to be so direct, but I want to make sure other people not familiar with Haskell don’t get the wrong impression. Haskell is explicitly designed to separate purely functional and stateful code with a clear inte…

Sorry for the additional pedantry, but I think this important to be precise about given the target audience of your comment. Monads aren't the separation between purely functional and stateful code. The Haskell type system maintains that separation. Anything that's doesn't return IO a for some a appears to be a pure function from the perspective of the programmer. Once a function returns IO a , there aren't any* func…

Note: The approach of structuring the interactions with the IO type with the functions (bindIO :: IO a -> (a -> IO b) -> IO b) and (returnIO :: a -> IO a) is still using the abstract idea of monads to organize the impure code and make it ergonomic to work with, so "monadic I/O" or "monadic state" aren't entirely misnomers. The thing I wanted to emphasize is that you don't need to know the word "monad" or understand anything in particular about the design process for the Monad typeclass in order to use these libraries.

I think focusing on the "monad" part over the "IO" part of "monadic IO" is particularly confusing to new users because the abstract idea of a monad is very general, so if you assume all places where it shows up are basically like the case of IO, you will be very confused. Further, it makes the idea of a monad seem like a Haskell-specific hack, rather than a general abstraction that can be used in any programming language you want to.

This is particularly important to emphasize because the abstract idea of monads only makes the IO approach to impurity nice to use, it doesn't make it possible. Haskell had I/O (and other impure capabilities) before the monadic way of organizing impure code was introduced. The heavy lifting for IO is done by having a type system strong enough to prevent a function of type IO a -> a from being written by an end-user. If you have written a monad abstraction in a language without such a type system[0], it can still be a nice abstraction, but it doesn't guarantee that pure and impure computations can be distinguished on the type level.

[0] https://www.nurkiewicz.com/2016/06/functor-and-monad-example...

Re: Why GitHub used Haskell for Semantic

#180
post #143
post #55

Earlier quoted context omitted.

I've worked in Elm a decent bit, and used PureScript a little. Elm is a very opinionated language - it's very deliberately missing some abstraction power (typeclasses), and some functions that are the bread-and-butter of every functional programmer have steadily been getting removed from the base libraries, so if you're used to Haskell, you'll find yourself falling back to duplicating code by hand a lot. Elm also mak…

> indentation preferences are strictly enforced. It's basically taken an awkward edge-case from Haskell's indentation rules and made it not only a requirement, but a prerequisite to seeing if there are any other errors in your program. Some parsing is less efficient than Haskell because Elm doesn't have 20+ years of PhDs working on it, but there is no such thing as compiler-enforced formatting. I can't think of compi…

The omission of where clauses was explicitly a stylistic choice[1].

This is perfectly valid Haskell:

    #!/usr/bin/env stack
    {- stack script --resolver lts-12.19 -}
    data Test = Test {count :: Int}
    
    test = let
      something = Test {
        count = 5
      }
      in 5+(count something)
    
    main = putStrLn $ show test

To get the equivalent Elm to compile, it must be indented like this:

    test = let
               something = {
                 count = 5
                 }
      in 5+(something.count)
Note that `something` must be indented beyond the beginning of `let`, and the closing curly brace must be indented to the same level as `count`. These are both not a warning, but a parse error - you can confirm it with Ellie[2]. If that were due to a lack of resources, it would absolutely be understandable, but this also was an explicit choice[3] which developer time was spent implementing.

[1] https://github.com/elm/compiler/issues/621

[2] https://ellie-app.com/5KRg4g5ZMkba1

[3] https://github.com/elm/compiler/issues/1573

Post reply on HN