17 ms·
Why GitHub used Haskell for Semantic
- spopejoy 7y ago> it's worth mentioning that Semantic, as a rule, does not encounter runtime crashes: null pointer exceptions, missing-method exceptions, and invalid casts are entirely obviated, as Haskell makes it nigh-impossible to build programs that contain such bugs. This I think is the real drug of Haskell. There are lots of challenges involved with moving to Haskell for production software, and the article notes some of them. But once your code builds and you ship -- man, there is nothing remotely like it. v1.0 software running for weeks in prod without a bug. Then, the super-sauce is: maintainers don't break your already-working code. Sure new code might have bugs, and deep semantic changes to code can break anything, but workaday fixes to one corner of the codebase simply can't break all the other corners. v2, v3, v4 all migrate to production with none of the working stuff falling over. PS I don't buy that the "control flow" feature couldn't have been done in Java -- however I would bet huge dollars that you couldn't do it in a way that wouldn't require massive investment in maintainers understanding a complex and subtle data-driven control flow pattern that any single dev could easily subvert, intentionally or not. I was a huge fan of FP-style coding in Java, but it required buy-in from all maintainers; as soon as somebody got lazy and went back to mutability etc there was nothing to stop them.
- emilypi 7y agoThere's another "real drug" hidden in the subtext of your post and Semantic's post, right in between "Sure new code might have bugs, and deep semantic changes to code can break anything..." and "Its language features allow concise, correct, and elegant expression of the data structures and algorithms we work with." - the notion that fundamental abstractions (not just the ones someboy thought up like the Gang of Four) compose well. This is something that we've seen the industry slowly migrating towards in the form of functional JS flavors like typescript and purescript, Java's lambdas, Scala's Cats and so on. The ability to refactor and as importantly be confident that your refactor is not messing with the semantics of anything upstream is a hidden feature of static types applied to expressive abstractions. So far, I have only seen this achieved with Haskell's libraries, type system, and reliance on fundamental mathematical concepts while also being able to avoid any "there's something rotten in Denmark" moments. The content in the Hackage ecosystem is a wonder of the modern programming world, warts and all. There are many rough edges to the development process, as always, but at least in Haskell you can limit the language's contributions to that edgeset. It actually makes you want to produce good code and be a better developer as a result!
- mcny 7y agoRequest change to Why Github uses Haskell for its newly released Semantic package
- StavrosK 7y agoWhy?
- jonahx 7y agoBecause in its current form the subject and verb don't agree.
- StavrosK 7y agoOnly in American English. Groups are plural in British English. "The police are corrupt" vs "the police is corrupt".
- theli0nheart 7y agoI have no idea if what you're saying is generally true, but I can say with certainty that no one would ever say "the police is corrupt" in American English.
- mlthoughts2018 7y agoA better example might be a British soccer club, e.g. Chelsea are corrupt.
- harry8 7y agoThe police force are corrupt vs the police force is corrupt.
- outside1234 7y agoThat second example is not valid in any English.
- jrockway 7y ago> given Go's lack of exceptions, such a feature would be entirely impossible. Haskell is a nice programming language, but ultimately if a program written in language A can run on your computer, a program can be written in language B that can run on your computer and do the same things. If you think "return foo, err" is a lot different than return "Left foo" or "Right err", then you might want to think more about how you think about computer programs.
- whateveracct 7y agoIf you think those two things are the same, you're just in the wrong. This isn't an opinion thing - I can easily prove that the Haskell way is strictly more precise than the Go way! Not all Turing complete languages are the same. Curry-Howard shows that. Haskell's type system subsumes Go's and allows you to express richer propositions about program behavior.
- deleted 7y ago[deleted]
- _bxg1 7y agoPedantry is unhelpful. Technically this project could be written in assembly. Have fun doing that.
- macintux 7y agoThe point isn’t that the software couldn’t be written in Go; it’s that the language feature that makes that particular problem easier to deal with doesn’t exist. You could write this tool in Go, but it would have an entirely different flow.
- dllthomas 7y agoIf you think x * y is a lot different than x + y, then you might want to think more about how you think about algebraic expressions, yeah?
- harry8 7y agoimplement x * y with no * using only + ans = 0; for(i = 0; i !=y; ++i) { ans += x; } Turing completeness is a thing. For a particular data transformation language A might be easier to write than language B. Language C easier to read. Language D easier to maintain, Language E less chance of a latent bug. And language F might be brainf&^k. As soon as you think about it as a data transformation and note you can write an interpreter an any language A,B,C,D,E... to execute any other of those languages source code it becomes obvious.
- _bxg1 7y agoI'm really curious why Haskell has seen so little adoption in industry. Is it just the difficulty? Or a chicken-and-egg effect with tooling and libraries? One thing I've wondered is if it actually isn't ideal for a lot of cases. FP is beautiful for certain things. But in some domains (or pieces of domains), state and mutation aren't just unfortunate implementation details, but a core element of the problem space. For these cases, the FP answer is usually "recompute and replace" (generally with immutable data structures that make this efficient). This can be syntactically clunky when it's a major part of your application, and not just a necessary evil to be swept out to the edge. 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).
- develop7 7y ago> Is it just the difficulty? It's loads to unlearn for most of programmers and a perfectly natural knee-jerk reaction of a refusal to. I mean, the more one knows already, the more is the desire to reuse such knowledge. Well, at least I have been there. > Haskell doesn't, really (from my cursory reading about it). Of course it does, https://en.wikibooks.org/wiki/Haskell/Mutable_objects https://en.wikibooks.org/wiki/Haskell/Mutable_objects looks a good start.
- tathougies 7y agoI 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.
- _bxg1 7y agoTo 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 seemingly forcing you to push all your imperative code up to the surface layer of your otherwise pure program, which sounds great unless you need to do really meaningful things that are by nature imperative.
- dmix 7y agoSeems to be the same reason Facebook used it and one of the well-worn areas that Haskell has proven itself (language parsing/analysis). The section about their day-to-day experience of programming serious software with Haskell compared to other languages is really interesting though.
- phodge 7y ago> 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 exceptions, such a feature would be entirely impossible. Not knowing much about FP, It'd be great to see a more in-depth article explaining this problem domain a bit more and showing some side-by-side examples of Haskell's specialized call sites compared to a Java try/except/finally solution (although Python would be a better procedural exception-based language to compare to) One of the main reasons I don't care much about Haskell is because without any side-by-side comparisons of Haskell vs <insert procedural language> 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.
- k6k7f7uky8ki 7y agoYou mean examples like Rosettacode has?
- cstrahan 7y agoNot Java or Python, but here’s some Ruby: https://www.honeybadger.io/blog/how-to-try-again-when-exceptions-happen-in-ruby/ https://www.honeybadger.io/blog/how-to-try-again-when-except... The above article talks about exploiting Ruby's support for call/cc to do something similar. A noteworthy difference: Ruby's support for call/cc is baked into it's runtime, while in Haskell you can implement call/cc as a normal library. This is done by leaning on Haskell's monadic "do" syntax and a suitable implementation of the Monad class. http://hackage.haskell.org/package/mtl-2.2.2/docs/Control-Monad-Cont.html http://hackage.haskell.org/package/mtl-2.2.2/docs/Control-Mo... I'm rooting from my phone, so I can't type up a this-vs-that. But maybe that piques your interest and you can read up on Haskell and programming with monads.
- hardwaresofton 7y ago> One of the main reasons I don't care much about Haskell is because without any side-by-side comparisons of Haskell vs <insert procedural language> 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 tell how much of an improvement it is unless you try it. Also, people who write haskell are more inclined to share lofty/abstract/interesting-to-other-haskellers code rather than your normal day-to-day code that is massively improved/safer and benefited from haskell's features. I've mentioned this before, but one example of where it became apparent to me how much haskell had changed what I expected from language was non-nullable types. It's starting to be really common in languages now (typescript, kotlin, etc), but if you are used to writing imperative languages, the worry of nil/None/null is ever present, and a concept like Optional<T> is actually quite foreign looking. If you really think about it, it means that none of your language is safe -- none of your functions are safe because they said they wanted a String but you might have gotten a null that looks like a String to the typechecker and will blow up at runtime. Another key improvement in haskell is the removal of class-based code-sharing (i.e. inheritance) -- the separation of behavior and data is really important, and most languages are starting to come around to this now (go w/ structs + interfaces, java w/ data classes, kotlin w/ data classes, rust w/ structs + traits), but haskell (and other ML languages) have been there for a while. Yet another key improvement in haskell is the errors-as-values paradigm that is everywhere. If some function has a possibility of failure, then it should return `Maybe TheThing` or `Either AnError TheThing` (see how nice and legible those types are?) -- this forces explicit checks on failure and allows cases where there isn't a chance of failure (just `TheThing`) to speed ahead without nullchecks and be fairly certain. This actually pressures you into trying to sequester failure across your codebase -- you try to write functions that have signatures like `TheThing -> SomeArgument -> OtherThing` (see how legibile that is?), to minimize on the amount of `Maybe x` or `Either error x` you have to deal with -- this is often if not always good for codebases. Maybe this is something I can help with, I write about pedestrian haskell a bunch, and I've been meaning to do a blog post on why haskell is better <your language>, something to really rustle the jimmies. BTW, the quote about resumable exceptions is actually referring to a concept called a monad, which can be incredibly hard to grasp if you don't look in the right places (there are a lot of bad tutorials out there), or don't give your brain long enough to marinate in the concepts. If I were to take a stab at explaining it simply, in this case it's like a combination of exceptions-as-values (i.e. not go's approach, and not java's approach) and the value that is being passed around has enough state in it to continue stop, fix itself, whatever else. When something goes wrong in most imperative languages, you kind of get the hell out of dodge, and you lose access (usually) to whatever work was done up until the function boundary -- it doesn't have to be this way but it usually is.
- tottenhm 7y ago"Semantic" looks pretty neat. Are there are previous threads or announcements about Github's goal in developing it (i.e. services for which they plan to use it)?
- spatulon 7y agoI saw on Twitter[1] that they're using it to show which methods/functions changed in a pull request[2]. [1]: https://twitter.com/rob_rix/status/1134537990095720450 https://twitter.com/rob_rix/status/1134537990095720450 [2]: https://github.blog/2017-07-26-quickly-review-changed-methods-and-functions-in-your-pull-requests/ https://github.blog/2017-07-26-quickly-review-changed-method...
- dev_dull 7y ago> Semantic is a singular project and we often find ourselves at the edges of modern computer science research. This is exactly where I DONT’T want to be when creating production software. If that’s thrilling to you then by all means. As for me, I like my software boring.
- nullwasamistake 7y agoI don't understand why they didn't use Java with ANTLR. It can also generate parsers in many other languages, but Java version supports more advanced stuff. There's already parsing support for many languages, and the parser itself is world-class. It's used internally by tons of systems. https://en.m.wikipedia.org/wiki/ANTLR#Projects https://en.m.wikipedia.org/wiki/ANTLR#Projects I mean, I guess Haskell is cool, but their critism of Java sounds like more of a design choice than a deal breaker. Did they really need to reinvent this wheel in an unpopular language where almost nobody can reuse/improve their work? I don't mean to be dismissive, but when your plans are to open source something corporate sponsored, you should do it in a way that benefits the community significantly. There's 20 other languages they could have chosen that fulfilled that objective better
- saghm 7y ago> I don't mean to be dismissive, but when your plans are to open source something corporate sponsored, you should do it in a way that benefits the community significantly This is a super weird objection to me; is your argument that open sourcing something that might not be useful to others is worse than just keeping it closed-source? Even if literally nobody else ever gets any use from this, I don't see why it's harmful for it to be open sourced. More generally, I feel like companies releasing everything that they don't have a strong business reason not to as open source is strictly positive.
- nullwasamistake 7y agoMore if you're going to open source something that widely useful you should write it in a common language. Otherwise the public benefit to open sourcing it is less. In this case, the project is almost as useful as binaries. It's unlikely that many will able to integrate into existing systems or even have the Haskell skills to work with it
- saghm 7y agoI guess I just have a fundamentally different view on open source than you. I don't see anything wrong with a company writing a tool in the way that is best for them given their current circumstances (e.g. skills of the team working on it) and then open sourcing it. The team that wrote this obviously felt that Haskell was their best choice for this project, and I don't begrudge them for open sourcing it just because it might not be useful for others.
- mlazos 7y agoThe control flow section perplexed me a bit, just because you can embed a DSL in Haskell with monads doesn’t mean that “control flow isn’t embedded in the language”. You still have a main entry point and all functions are executed top to bottom albeit with lazy semantics. You could write a DSL and interpret it with C# with all of the properties they want. Haskell is better for this sort of task but their reasons seemed off. Am I misunderstanding that section?
- willtim 7y agoUsing C# as an example, foreach and IEnumerable are baked into the language as is try/catch and more recently Async/Await. These are all just library functions in Haskell and often more general (e.g. forM in Haskell works for any Monad not just IO). Because they are library functions they can be changed/customized very easily. In C#, how could foreach be made to support a different stream type, exceptions be made checked or Async/Await be made to suspend across stack frames? For this reason, Haskell is probably closer to a general purpose language than many of the imperative systems programming languages (especially Go).
- bakhy 7y agoC# has LINQ. Implement Select and SelectMany extension methods for whatever you like, and you can use the LINQ syntax with your type just as easily as with IEnumerable. Foreach and async/await are baked in, that's true, but the LINQ syntax is easily extendable to new use cases.
- ddellacosta 7y agoI wonder why this is? https://www.infoq.com/interviews/erik-meijer-linq/ https://www.infoq.com/interviews/erik-meijer-linq/ (from "3. How does LINQ work?") What we have done, and what the mathematicians call Monads, we have identified these sets of operations, we call them standard query operators; we have a list of about 25 standard operators that you can apply to any data model.
- lmm 7y ago
- namelosw 7y agoThis week I need to do some crazy validation in C#. I wrote a bunch of plain imperative code. Then I thought I could use applicative validation with LinQ. I tried to wrote Maybe, Either and Validation, and wanted to extract an applicative and monadic interface. Then I found there are huge pitfalls and difficulties to do it properly. I also tried the same thing in JavaScript, while it's not a safe language, but the equivalent idea is quite easy to express. The thing I found disturbing is typical static typed languages limit our expression of imagination. Every now and then I work in Java or C# project, when I tried to express some abstract I would mostly face some difficulties. When I tried to express those ideas to colleagues they mostly didn't think about those things ever. On the other hand, the dynamic nature of JavaScript (of course Ruby and Python, etc) make things easier to express and try new ideas. I can express new ideas to dynamically typed languages programmer much easier. There's definitely "box" for programming languages which prevents people from thinking "out of the box". A lot of people tend to think of Haskell as a Perlis language. And I think statically typed languages without a flexible design makes Anti-Perlis languages.
- stevejb 7y agoThis is an interesting perspective. I write Haskell for fun, and sometimes for profit. My first language that I wrote in professionally was Perl 5, so I definitely understand what you are saying about the dynamic types. However, in practice I have come to the opposite conclusion. When I use a dynamically typed language, I can't escape the looming fear that I am creating a mess for myself that, if I want to use for anything non-trival, I will have to clean up later. In Haskell, I find it very freeing because I can keep writing and as long as the types work out, the "mess" is contained and my play code has a much better path to maturing.
- lmm 7y agoIt sounds like you're trying to judge Haskell based on your experience of Java and C#? Don't do that. The Java/C# type systems have substantial limitations, but that's not a problem of type systems in general, it's a problem of C++-family languages specifically.
- 7y ago
- gluegadget 7y ago> Editor tooling is sub-par (especially compared to language communities like Java and C#) and finicky - we often end up just compiling in a separate terminal. https://github.com/ndmitchell/ghcid https://github.com/ndmitchell/ghcid is a great tool that does exactly the last part.
- Insanity 7y agoApart from being a great language, Haskell also has a great community. I recommend learning the lang and interacting with the people (irc, #haskell on freenode for example). :)
- norswap 7y agoI don't like these posts (for any language, not only Haskell). Invariably they will list many points, most of which are subjective or tangential. There are one or two core points (here I guess it is "Control Flow") that would benefit going into much deeper. I think, you'll find these points aren't as solid as they appear (cf. other threads in the comments). Using Haskell is fine. You don't have to justify it. It's enough to like it, being comfortable and productive with it. Own your gut. Don't make pseudo-truth argument lists to justify your decisions.
- mebassett 7y agoI agree with you. It's sufficient to like using a tool and be productive with the tool to justify using it. But sometimes, solid engineers who are productive with certain tools are working at the behest of unenlightened managers. Articles that say "BigCo uses X for Y because of Scientifically Sounding Reasons" help those engineers use the tools they like and are productive in.