10 ms·
Why ML/OCaml are good for writing compilers (1998)
- vmasto 9y agoFor anyone interested and isn't aware yet Facebook is developing Reason, a layer over OCaml. I've been fiddling with it for the past couple of weeks and coming from JavaScript I personally found the experience generally enjoyable. https://facebook.github.io/reason/ https://facebook.github.io/reason/
- adriancooney 9y agoThat was an extremely pleasant and convincing introduction, thank you for that. I'm definitely going to give this a try in future projects.
- mhink 9y agoHah! Thanks for the link- I discovered this gem just now in their list of comparisons to JS syntax: Javascript | Reason --------------+---------------------------- const x = y; | let x = y; let x = y; | reference cells var x = y; | No equivalent (thankfully)
- vmasto 9y ago:) Yeah, unfortunately JavaScript can only be improved by educating people not to use the horrible parts (rather than fixing/deprecating them which is not possible). const and let were extremely necessary.
- Dangeranger 9y agoAfter learning Elm I wanted to understand ML/OCaml a bit more, so I worked through some documentation from the OCaml site and walked away pleasantly surprised. After using it for a couple of weeks I am confused why ML/OCaml aren't more popular. They are safe, functional, stable, fast, and have great tooling. They seem poised to take over the functional domain. While the syntax took a little getting used to ( emphasis on little) once you are used to it, it's very natural. Union types are wonderful, and the implicit type safety within programs was nice.
- akhilcacharya 9y ago>After using it for a couple of weeks I am confused why ML/OCaml aren't more popular For me, the issue is the GIL, although that is being worked on as we speak.
- nv-vn 9y agoSadly, I'm starting to lose my hope over multicore. It's been in the works for as long as I've used the language with much speculation of it being "almost done" or "in the next release" that have failed to materialize. That said, I don't have the time to really follow along with the compiler's development so take that with a grain of salt.
- 59nadir 9y agoPrecisely this is the reason I've lost hope with regards to OCaml as a main language. Multicore, specifically, is one of those things that has been "close" for so long that it's looking like a Duke Nuke'em Forever feature. I keep track of OCaml regularly because I love the language and I find that it's probably the best combination of features in one place, both in terms of my enjoyment as a programmer and in terms of the performance of the language. I've come to realize later, though, that there's one glaring problem: Runtime inspection really is much more valuable to me than clean syntax and programmer comfortability when I'm building a system. With that in mind, maybe it'll never be very interesting to build a bigger system in a language like OCaml, even though it offers you a lot in terms of programmer efficiency as well as high performance. Maybe it's better to glue together OCaml programs on the BEAM (The Erlang VM) so that you're able to orchestrate them and introspect them and get proper handling and oversight of the different components of your system. Maybe all that makes multicore in OCaml mostly pointless for you in practise. Of course, not everyone will use the BEAM and OCaml together, so for them it matters a lot. I've come to see it as a worrying sign of a community that doesn't care to evolve enough, more than anything, and that's why OCaml is not as interesting as it could be. It should be said that languages that supposedly are made for building systems also lack this runtime introspection and oversight. They have no way to locate and refer to their threads and no way to automatically handle their successes and failures. These languages are wildly popular, and so none of the above apparently matters to the vast majority of people. I think it's an interesting argument around (or against?) multicore in OCaml.
- nv-vn 9y agoThe problem with this article is that it's missing an answer to why one would choose ML/OCaml over Haskell. Haskell has many more features, a more advanced type system, arguably superior syntax, and much better library support. However, I believe that OCaml/SML are often a better choice for a number of reasons. First of all, OCaml/SML are the best choice in terms of example code for compilers. They're historically the choice of many compiler/interpreter/type theory texts (Types and Programming Languages, Modern Compiler Implementation in ML, and an ML is even used as a language to interpret in Essentials of Programming Languages). Andrej Bauer's PLZOO is also written in OCaml. Equally important is the fact that there are a variety of ML implementations, all of which are much more approachable than GHC. The OCaml compiler's codebase is a reasonable size that an individual could get a good idea of how it works in a few weeks or so. SMLNJ, MLKit, MLton, CakeML are all open source and on Github, and all seem to be fairly approachable in comparison to the monolith that is GHC. And that's not even mentioning other compiler in ML (Haxe, Rust's bootstrap compiler, Facebook's Hack compiler, etc.). The fact that there are real-world compilers with perfectly approachable code bases (even without great familiarity with the language; compilers in Haskell might require an in-depth understanding of many of the core type classes and language extensions available) that are open source is highly attractive to novice compiler writers. Additionally, the feature set in MLs is a good choice for compilers. While they lack some of the cooler features of Haskell, MLs make up for it in simplicity; lots of the features in GHC's type system (especially with language extensions) mean very little for 90% of compiler writers, and getting rid of them from the get-go helps keep the code small and easy to reason about (even if you won't have as much type safety in the compiler itself). This also means that there are a lot less ways to do a single thing, which can be nice when you're not sure exactly how you're going to implement a certain feature. However, one thing I really find incredibly useful is OCaml's polymorphic variants. These are pretty much perfect for statically enforcing a nanopass-like system in your compiler and are a great way of designing your AST/data types in your compiler. I feel like this gets passed up a ton (as far as I know I'm the first person who's used them to create nanopasses), but it's quite convenient and makes OCaml a good competitor for Scheme in this regard.
- deleted 9y ago[deleted]
- 9y ago
- kornakiewicz 9y agoI'm a relatively young developer (three years older than Java) and don't fully get the thing about exceptions (point 7). It sounds very familiar to the solution I know from Java, and it does not make safety - or even feeling about it - any better. If you can still write code that can throw exception and an explicit assurance about it is the only way to prevent the crash, it doesn't change anything, actually. P.S. I'm not really familiar to ML/OCaml, but have decent experience with large code bases in languages that are not very keen to protect you from yourself.
- gizmo686 9y agoExceptions in ML languages are very similar to those in Java. The reason for that is simple: they are simply a good way of dealing with computations that might fail. Having said that, exceptions are best used (in any language) where you want to deal with the failure way up in the call stack. If you catch the exception right where it occurs, you should just use a safe method that reports a failure in the return value. Speaking as a Haskell programmer, never use exceptions. You can get away with this advice because the Either monad allows you to have the behavior of exceptions (namely, at any point you can "fail" a computation and have the error automatically propagate up to the handler). However, this approach relies heavily on having a type system more advanced than OCaml's in order to be reasonable.
- thedufer 9y agoThe Either pattern for errors works great in OCaml; most of the code I write uses it. I'm not sure what problem you're referring to.
- StrykerKKD 9y agoI agree that Ocaml is just extremely well suited for making new programig languages. If you are interested in Ocaml+programming languages check out the plzoo: http://plzoo.andrej.com/ http://plzoo.andrej.com/ I personally think that Ocaml is really good at this, because I started converting the Scheme examples from the PLAI book to Ocaml and it's just felt right(maybe because I'm not fan of the scheme syntax).
- agumonkey 9y agoFP is based on recursion, and recursive types, inductive algorithms are essential for linguistic processing and transformation.
- rbehrends 9y agoI'll note that some of the aspects don't necessarily work out like that in practice: 1. The GC part is true, but one has to remember that this was written at a time when GC was still a bit of an unusual feature in mainstream languages. 2. Tail recursion doesn't really make much of a difference for walking trees, which is recursive, but (mostly) not tail recursive. 3. OCaml in particular uses 63/31-bit ints due to implementation details, which isn't a good fit for 64/32-bit integers. The strings and bignum part is mostly right, though. 4. ADTs can be good or bad for describing ASTs. Once you enrich ASTs with semantics shared by all variants (such as source coordinates), inheritance can become a better fit than ADTs. 8. Type inference doesn't really extend to module signatures, which you have to write out explicitly (though tooling such as `ocamlc -i` allows you to let the compiler help you write them). I also generally find it better to explicitly annotate functions with types. Not only does it make the code more readable later in its life, but you get fewer truly impenetrable type error messages because you forgot parentheses or a semicolon somewhere. That said, there are several good points still.
- willtim 9y agoADTs and pattern matching are much more convenient and higher-level in practice than using OOP with inheritance. The visitor pattern, essentially just a fold, is the best one can do in an OOP language. With type-class abstractions and data type generic programming, the gap widens further. In Haskell, my current FP language of choice, I can implement a complex transform such as Lambda lifting in a few 10's of lines of readable idiomatic code.
- rbehrends 9y agoFirst, inheritance provides a strict superset of standard ADT functionality. Proof: Scala does ADTs through inheritance. ADTs are basically isomorphic to a closed two-tiered inheritance hierarchy with an abstract superclass at the top tier. Second, you're confusing inheritance with the ability to map subtypes to operations (and in statically typed languages, in a type-safe fashion). This is a function of OCaml's (or SML's, or Haskell's, or F#'s) pattern matching facilities, not of inheritance vs. ADTs. It can also be done with typecase statements, multi-methods (or actually, just external methods), or tree parsers. The tree parser approach in particular is more general and powerful than the typical pattern matchers in functional languages. Third, if you look at actual compilers, such traversal will commonly be done in an ad-hoc fashion and can be done equally well with bog-standard methods. Where you have generalized traversal mechanisms, the visitor pattern will crop up in OCaml, too (in some guise or another). Examples are the Ast_mapper module for PPX in OCaml itself [1] and the visitor interface in CIL [2]. The reason is that if you want to perform a generalized fold, map, etc. operation over a heterogeneous data structure such as an AST (visitor is usually fold + map due to destructive updates), you need to also provide a set of operations for the various types that you can encounter during traversal. [1] https://caml.inria.fr/pub/docs/manual-ocaml/libref/Ast_mapper.htm https://caml.inria.fr/pub/docs/manual-ocaml/libref/Ast_mappe... [2] https://people.eecs.berkeley.edu/~necula/cil/api/Cil.cilVisitor.html https://people.eecs.berkeley.edu/~necula/cil/api/Cil.cilVisi...
- hongbo_zhang 9y agoFor web developers who are looking for an industrial strength functional language instead of JS, OCaml probably has the best story here. Actually it has two OCaml->JS compilers of very high quality The first one, js_of_ocaml, could bootstrap the whole compiler several years ago(probably the first one there). The recent one, https://github.com/bloomberg/bucklescript https://github.com/bloomberg/bucklescript, push the JS compilation into next level, it generates fairly readable code, good FFI story, and its compilation is extremely fast, check out the compiler in JS version(http://bloomberg.github.io/bucklescript/js-demo/ http://bloomberg.github.io/bucklescript/js-demo/), and imagine how fast it would be for the compiler in native version. BuckleScript has a good story for Windows, and generates fairly efficient code, see benchmark here: https://github.com/neonsquare/bucklescript-benchmark https://github.com/neonsquare/bucklescript-benchmark BuckleScript is already used in production by big companies: for example Facebook messenger.com 25% is powered by BuckleScript, the new WebAssembly spec interpreter by Google is also partly cross compiled into JS by BuckleScript. Disclaimer: I am one of the authors of BuckleScript
- atombender 9y agoI'm optimistic about Reason, Facebook's new syntax "skin" on top of OCaml. I find OCaml's syntax to be quite gnarly; of the MLs, F# is probably the cleanest and most modern-feeling. Something like F# without the .NET stuff could have been amazing.
- haskellandchill 9y agoI find OCaml's syntax simple and clear. I don't get the reason for Reason, but hope it leads to more OCaml adoption.
- emmelaich 9y agoI get the reason* for Reason even though it may ostensibly be a superficial one. There was a post by someone on HN saying they started using Reason and ended up using straight Ocaml. * My earliest memories of attempting to use Ocaml was pasting something directly from a beginner's tutorial into ocamli and getting a baffling error message. I think it had to do with use of double semicolons vs single semicolons. Yet that wasn't mentioned in the entire tutorial.
- jackmott 9y agoOCaml has the potential to be great for almost everything with some work and a bigger ecosystems. F# as well (very similar). i can only imagine how great the world would be if a standard ml had accidentally become the web browser language and all that mind share had gone into evolving it and optimizing it and its tools.
- chairmanwow 9y agoCurrently taking a compilers course that uses SML/NJ and it has been an absolute delight. The functional paradigm is a little strange to get used to at first, but after a while its strong suits make themselves known. The trivial type inferences and pattern matching capabilities make it easy to efficiently describe complicated and precise program situations.
- hyperpallium 9y agoHow are simple parsers written in ML (or ocaml)? You can't use the coding style used for recursive descent in the Dragon compiler book, without using mutable variables. Do you have to use parser combinators, which have their own limitations?
- rubiquity 9y agoYou can do mutation in both Standard ML and OCaml. If I recall, Robert Harper's book on Standard ML starts off with a recursive descent parser.
- nv-vn 9y agoThe most common way is using a parser generator (ocamlyacc or menhir, both are basically interchangeable 99% of the time). Parser combinators are a choice, but honestly I think recursive descent parsers are more common than combinators in OCaml.
- mafribe 9y agoParser combinators tend to work by recursive descent, so cannot handle left recursive grammars [1], and tend to be really slow. The latter is not a problem for many applications, but removing left recursion can be irritating even for small grammars. It is possible to build combinator parsers that can handle all context-free grammars [2], but I'm not sure any of Ocaml's are built that way. In any case, Ocaml has parser generators that are fast, do bottom-up parsing (hence handle left-recursion without issue) and not based on parser combinators, e.g. ocamlyacc [3]. I'd use parser combinators for quick prototypes, and, if measurement shows a performance problem, replace them with a generated (e.g. by ocamlyacc) parser. As far as I remember the parser in Ocaml's (superfast) compiler is generated by ocamlyacc. [1] https://en.wikipedia.org/wiki/Left_recursion https://en.wikipedia.org/wiki/Left_recursion [2] T. Ridge, Simple, functional, sound and complete parsing for all context-free grammars. http://www.tom-ridge.com/resources/ridge11parsing-cpp.pdf http://www.tom-ridge.com/resources/ridge11parsing-cpp.pdf [3] https://caml.inria.fr/pub/docs/manual-ocaml/lexyacc.html https://caml.inria.fr/pub/docs/manual-ocaml/lexyacc.html
- ms013 9y agoIn production code we tend to use ocamlyacc or menhir. There is nothing about ocaml/ML that prohibits the use of the kind of parser generators one would expect in any other language.