579 karma · joined May 25, 2010
It really strikes me as another variation on the Carefully Curated Instagram Feed that contains a million pictures of some hustler douche skydiving or touring Africa, or something. Building engagement with the Personal Brand, etc. I mean, everybody kind of does it, but it's a new level of narcissism to write a blog post about how “I’m going to focus on #1 right now, which is me, and the fact that I am the only one who has anything worthwhile to say.”
If you really want to focus on knowing yourself and being reflective, that's great! But don't “broadcast”. Just be silent for God's sake.
Our userbase was TINY (so you think scaling should not even remotely be an issue), but we had constant downtime with Parse; not to mention we observed between 1% and 3% of all requests to Parse failing for obscure reasons (and it was never clear if it was just our node, or if it was global). I seem to recall the Parse team fixing these, and then repeatedly rolling back their fixes since they would inevitably cause something even more catastrophic to happen. I am sure all of them were working really hard, and I don't want to say anything to make them feel bad, but honestly, the class of problems that plagued Parse (at least at the time I was familiar with it) did not inspire confidence. It is possible that it is much better now; I have not used it in months.
Parse is a lot of fun for quick prototypes and demos, and I recommend it for that if you find yourself wanting to iterate quickly and repeatedly on such things, particularly if most of your "innovation" is happening on a client (like an iOS or Android app, etc.).
1. Reasoning by induction: not possible with a lazy function space
2. Non-pointed types: also not possible in Haskell
3. Compatibility with a proper treatment of effects
It's great that you can do strictness annotations in Haskell! But they don't accord one the above facilities at all.
BTW, I looked at your OCaml stuff yesterday, and it seemed pretty cool.
Debug.Trace is also unpredictable; actually, it's perfectly predictable if you understand laziness, but it's still not what's really wanted in most cases.
2. ST is a single instance of an effect that can be interpreted into "pure" code. There are plenty of other effects that don't work like this in Haskell, not to mention the problem of composing them together.
So thanks for chiming in! But what you have said is not really that different from what I have said.
> Consider the case of a set implemented as a binary tree. The type of such a set should be parametrised by the type of the elements and the ordering used. With applicative functors this is the case as your set type will be `Set(O).t` where `O` is a structure containing the type and the ordering. With generative functors each individual set type is abstract -- so the type itself is not parameterised by the ordering.
You make a good point about this not being strictly about type classes. But I'd say that the issue is only a problem in the presence of implicit resolution, since otherwise, you can just bind the result of the functor to a structure once and be done with it. It becomes an issue with type classes, because you don't have the choice to share a single structure during elaboration.
IMO, the generative version is still better for most use-cases (pure or not), but it's nice that you can have both in OCaml.
1. hiding constructors in files 2. type classes
But it doesn't really begin to approach the kind of structuring that is possible in an ML-like system. Unfortunately, the issue is very (needlessly) controversial, and I don't think I want to get dragged into it here.
I'll mention, though, that Haskell does have one form of modularity which ML doesn't really, which is the fact that you can write algorithms separately, compose them together after the fact, and expect to get reasonable performance in most cases. This is because of two things: haskell is non-strict, and GHC has pretty good fusion. In ML, you often end up manually fusing things together in order to get good performance, so composition can be a bit more difficult.
1. higher order functors.
2. modular type classes
Higher order functors are kind of cool, but IMO Standard ML does not seem to be suffering too much from the lack of them. I'm not too interested in it, since it gets super gnarly super fast, and this happens to be pretty much the main use-case for applicative functors. I suspect that most use-cases of higher order functors in OCaml could be reformulated to be first order, with a lot less monkeying around in the module system. There may be compelling use-cases though.
The other use-case is possibly a version of modular type classes that behaved a bit more like Haskell's. The idea is that if functors are going to be applied automatically during elaboration to provide something like type classes, you'll get MkWelp(S) called in multiple places, and you would prefer that any type members of the resulting structure be compatible. Applicative functors would do this.
I am not too convinced by this use-case, though I could see that people would find it useful.
In all other cases, generative functors have the correct semantics. Pretty much the whole use-case of putting abstract types in a functor is that you can then reason intensionally about them (i.e. distinguish them based on their access path). This is super useful, for instance, if you have a notion of "index" or something and you want to prevent yourself from using indexes from one table in another one, or something along those lines.
This is what the Scala people mystifyingly call "path dependent types". It's just generative abstraction.
So maybe it is an interesting feature to have applicative functors, but these should be added post facto, and generative functors should be the default. OCaml now supports generative functors if you add an extra () parameter; it's strange syntax, but it's good enough for me! :)
1. modularity (and now that they have added generative functors à la SML, you can have true abstraction)
2. benign effects: in Haskell "proper", you do not have effects; rather you have "codes" for effects, which get interpreted into effects by the RTS; this rules out the possibility of, e.g., using effects to implement a semantically pure interface. On the other hand, OCaml has actual effects, which can be used in an open-ended way to implement all sorts of functional interfaces.
3. strictness: arguments abound about whether laziness or strictness is better; for me, it comes down to the fact that with some pain, you can embed laziness in a strict language with effects, but you cannot embed full-on ML-style strictness into a language like Haskell; moreover, strictness-by-default permits safe uses of benign effects.
I'd call Haskell an expression-oriented programming language, since the types end up classifying expressions and algorithms (i.e. the particular "effects" you used get put into the type). Whereas I'd say (OCa)ML is a value-oriented language, since values (canonical forms) are considered separately from general expressions (canonical and non-canonical forms); moreover, implementation details don't end up in the types, so you can really consider them to be classifying values and functions (i.e. equivalence classes of algorithms, not algorithms themselves). This is largely orthogonal from strictness vs laziness, but as soon as you add partiality in, strictness becomes the only tractable way to have canonical-form-based meaning explanations for the judgements of the theory.
P.S. My day job is writing Haskell. (In case the Pedagogical Brethren wish to come and "correct" me.)
nope nope nope
You can do all the reverse etymology you want, but in the end, we all know this is just a word that JavaScript kids are using because it makes them feel cool.
This sort of reminds me of when that weird kid nobody likes tries on a new nickname (like "The Chief" or "Serpent" or "T") and I have to kindly say, “Hey bingo/bud, I'm really sorry, that nickname is just not happening".