Live data from Hacker News

Why ML/OCaml are good for writing compilers (1998)

flint.cs.yale.edu

101–110 of 151 posts

Re: Why ML/OCaml are good for writing compilers (1998)

#101
post #6

The 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 th…

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

Nice, I was just asking about this on the nanopass list the other day, do you happen to have a publicly available example of this anywhere?

Re: Why ML/OCaml are good for writing compilers (1998)

#102

Earlier quoted context omitted.

> 3. OCaml in particular uses 63/31-bit ints due to implementation details, which isn't a good fit for 64/32-bit integers I'm not sure what "isn't a good fit" is supposed to mean.

Try storing an integer literal that requires 64 bits in a variable that can hold only 63 bits. It's not going to make it impossible (you may just need something like a ShortIntLiteral and a LongIntLiteral variant), but it's going to require additional effort.

Sure, but not many real programs actually need the full 64-bits. Many of the ones that may seem to require the full bit width are doing bit ops on larger bit streams, for which there's ocaml-bitstream. What sort of programs are you thinking of?

Re: Why ML/OCaml are good for writing compilers (1998)

#103

I'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…

Exceptions 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.…

The 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.

Re: Why ML/OCaml are good for writing compilers (1998)

#104

Earlier quoted context omitted.

I'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.

>I find OCaml's syntax to be quite gnarly What's wrong with the OCaml syntax? It's much more clean than say scala's one, it's indentation insensitive, and a' list feels more relevant than the list

One problem is that it is full of shift-reduce conflicts, due to a lack of an "end" token in most expressions.

The one that bugs me the most is nested match expressions, which often need to be wrapped in parenthesis.

Re: Why ML/OCaml are good for writing compilers (1998)

#105
post #82
post #11

Earlier quoted context omitted.

Also, Haskell is something of a soup of DSL-operators that require one spend significant time researching what they mean and what behaviour they induce. Even with such knowledge, it suffers from the Perl-ish woe of write-once and read-never.

Wholly disagree. Yes in Haskell you can define operators yourself (they are just functions but made out of special characters and placed after the first argument, e.g.: "Hi " ++ username); and this is often done by Haskellists. So you sometimes need to learn a few new operators that come with a library to WRITE code using that lib; but in order to READ code I rarely need to ref the docs, it is just evident from the c…

shrug When I look at Haskell code I see overly terse expressions and nothing resembling the concept of self-documentation.

Re: Why ML/OCaml are good for writing compilers (1998)

#106

Earlier quoted context omitted.

Try storing an integer literal that requires 64 bits in a variable that can hold only 63 bits. It's not going to make it impossible (you may just need something like a ShortIntLiteral and a LongIntLiteral variant), but it's going to require additional effort.

Sure, but not many real programs actually need the full 64-bits. Many of the ones that may seem to require the full bit width are doing bit ops on larger bit streams, for which there's ocaml-bitstream. What sort of programs are you thinking of?

Umm, compilers? That's what the post was about. Compilers need to be able to represent integer literals up to machine precision.

Re: Why ML/OCaml are good for writing compilers (1998)

#107
post #76

Earlier quoted context omitted.

ADTs 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…

First, 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…

Inheritance may be a theoretical superset of ADTs, but it is not as convenient due to the complexity of subtyping and problems with its inference. Scala is the proof of this.

Both extensible records and open recursion can be achieved with ADTs, so why do we need inheritance with all its problems? You still haven't explained this.

I lumped inheritance and OOP together as this is what is typically packaged and available for us to use.

It is true that more principled traversals (e.g. catamorphisms) only match one level deep, but pattern matching is still a convenient and high-level syntax in such cases. Pattern matching would also complement e.g. attribute grammars.

Re: Why ML/OCaml are good for writing compilers (1998)

#108
post #21

Earlier quoted context omitted.

Just to clarify, it's not concurrency that's the issue but parallelism. You can write nice concurrent code pretty easily, but writing code that runs on multiple cores is still a problem. Also, if you're interested in using OCaml for web programming, there is some pretty cool stuff you might wanna check out [1] [2] [3]. That said, there's no great solution to the lack of macros :/ [1] https://github.com/dannywillems/o…

Strictly speaking, it's not parallelism, but multi-threaded code that operates on shared memory and which is not limited to arrays over scalars.

You're talking about data parallelism, the OP is talking about task parallelism. Since in both cases things are occurring in parallel it makes sense to use 'parallelism' as an umbrella term for both and it was clear from context here that it was task parallelism under discussion.

Re: Why ML/OCaml are good for writing compilers (1998)

#109

Earlier quoted context omitted.

First, 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…

Inheritance may be a theoretical superset of ADTs, but it is not as convenient due to the complexity of subtyping and problems with its inference. Scala is the proof of this. Both extensible records and open recursion can be achieved with ADTs, so why do we need inheritance with all its problems? You still haven't explained this. I lumped inheritance and OOP together as this is what is typically packaged and availabl…

> Inheritance may be a theoretical superset of ADTs, but it is not as convenient due to the complexity of subtyping and problems with its inference. Scala is the proof of this.

Scala isn't proof of this, because so much of the complexity of Scala's type system is due to a desire to provide smooth interoperability with Java's, which requires the replication of and dealing with some of the more misguided aspects of Java's approach. (The biggest one is probably that Java's constrained parametric polymorphism is intimately tied to a form of nominal subtyping that is simultaneously too constraining and not expressive enough for a number of use cases, leading to things such as implicit arguments and CanBuildFrom in Scala.)

> Both extensible records and open recursion can be achieved with ADTs, so why do we need inheritance with all its problems? You still haven't explained this.

My general argument would be that any single approach to polymorphism will be insufficient to cover all use cases, many of which have mutually incompatible requirements:

1. You may want to be able to exhaustively enumerate operations on a type or subtype for purposes of code verification or optimization.

2. You may want to be able to add additional operations to a type or subtype for purposes of modularity or extensibility.

3. You may want to be able to exhaustively enumerate subtypes of a type for purposes of code verification or optimization.

4. You may want to be able to add additional subtypes to a type for purposes of modularity or extensibility.

5. You may want to resolve polymorphism at runtime.

6. You may want to resolve polymorphism at compile-time.

ADTs present you with a closed universe of subtypes and an open universe of operations as well as runtime polymorphism. In other words, they meet half of the above criteria.

Haskell's approaches to extensible records and open recursion cannot square the circle, either. They require their own mechanisms and/or hacks on top of ADTs and have their pros and cons that are distinct from the pros and cons of using inheritance. There is no single mechanism for polymorphism that can do it all. (OCaml, incidentally, has at least six distinct polymorphism mechanisms that support runtime polymorphism: ADTs, polymorphic variants, open types, records of closures, first-class modules, objects.)

A simple example of something that basic ADTs just don't do: add more variants (subtypes in the OO case) to the type. You can go with something like OCaml's polymorphic variants, but that doesn't make it easy to extend existing operations in a modular fashion as you add more variants. If you want to simulate OO-style extensible late binding in Haskell, you'll generally need {-# LANGUAGE ExistentialQuantification #-} and type classes.

Inheritance, incidentally, does not inherently present more or less problems than other approaches. That it does not fit neatly in the Haskell universe is the result of various constraints and preferences within Haskell's design, just as some of Haskell's mechanisms fit poorly into other languages. These are not universal problems; this is about language design constraints.

Re: Why ML/OCaml are good for writing compilers (1998)

#110

Earlier quoted context omitted.

I'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.

Fable: http://fable.io/ It's able to self-host as well. Check it out at http://fable.io/repl F# also runs on .NET Core, which is cross-platform and comes with a good CLI. Documented, too: https://docs.microsoft.com/en-us/dotnet/articles/fsharp/tuto...

Fable looks great, and I might try it out, but I was thinking more along the lines of native, static compilation.
Post reply on HN