[HN Gopher] What I wish I knew when learning OCaml (2018)
       ___________________________________________________________________
        
       What I wish I knew when learning OCaml (2018)
        
       Author : cribbles
       Score  : 107 points
       Date   : 2022-04-30 21:28 UTC (3 days ago)
        
 (HTM) web link (baturin.org)
 (TXT) w3m dump (baturin.org)
        
       | pmoriarty wrote:
       | I tried OCaml a long time ago, and one of the things that really
       | turned me off of it was all the inscrutable error messages. I
       | went to #ocaml on Freenode for help, and when I had the error
       | messages explained to me I asked how the person who explained
       | them knew what they meant. He told me that the reason he knew was
       | because he took a couple of semesters of type theory courses at
       | his university. I didn't want to have to take a couple of
       | semesters of type theory courses in order to be able to program
       | effectively in this language. I hope the situation has improved
       | since then.
       | 
       | The other thing I didn't like (which was something shared with
       | other statically-typed languages) was feeling like I had to
       | wrestle forever with the compiler to get my program to run. It
       | just always felt so much easier to write programs in dynamically
       | typed languages. Sure, my programs might have bugs in them, but I
       | could iron them out over time, and my programs change so much
       | anyway that pieces of buggy-but-working code in those dynamically
       | typed languages might be replaced wholesale anyway before I even
       | ran in to the bugs.. so the pace of prototyping in dynamically
       | typed languages is much faster, in my experience.
        
         | yodsanklai wrote:
         | I think both of these points can be alleviated with certain
         | coding habits that come with practice. For instance, adding
         | type annotations in some places will help with error messages.
         | And using "assert false" (which has type 'a) will let you run
         | an incomplete/broken program.
         | 
         | As for the error messages requiring expertise in type theory,
         | it sounds as an exaggeration, esp. when not using advanced
         | features.
        
           | baby wrote:
           | Ah! Didn't know the `assert false` trick. I believe `failwith
           | "..."` will not always allow you to run the program
        
           | kragen wrote:
           | Hey, thanks for that "assert false" trick! I never knew that!
           | 
           | I don't know much about type theory but I did eventually
           | manage to learn to interpret OCaml's type errors well enough
           | to get things to compile. It still feels like driving a car
           | by scraping it along a highway guardrail but it's often
           | better than testing. I have to write twice as much code as in
           | Python, it takes me longer to get it to run, and I still
           | can't call it from C or Lua, but it runs twenty times as fast
           | as Python and the process of thinking through the types helps
           | me a lot to write code that works.
           | 
           | I keep hoping I'll internalize the type system enough that my
           | programs run the first time they way they do in Python, but
           | it hasn't happened yet.
           | 
           | I still often write a prototype in Python, though.
        
             | legobmw99 wrote:
             | OCaml also has a built in function failwith: string -> 'a,
             | so you can print an error in those cases. If it's a code
             | path you ever think will execute, failwith "some error
             | here" is probably better than assert false
        
           | pmoriarty wrote:
           | _" adding type annotations in some places will help with
           | error messages."_
           | 
           | I annotated the hell out of my programs, and completely
           | avoided OCaml's type inference as much as I could because I
           | saw that it could not guess what I meant. I still had tons of
           | problems understanding the error messages.
           | 
           | Error messages like _" This expression is of type X but an
           | expression was expected of type X"_ were not uncommon, and
           | super frustrating.
        
             | gmfawcett wrote:
             | > Error messages like "This expression is of type X but an
             | expression was expected of type X" were not uncommon, and
             | super frustrating.
             | 
             | That particular error message has been gone from OCaml for
             | years now.
        
             | WastingMyTime89 wrote:
             | > I annotated the hell out of my programs, and completely
             | avoided OCaml's type inference as much as I could because I
             | saw that it could not guess what I meant.
             | 
             | The type checker and the type inference parts of the
             | compiler are one and the same. If the type checker can't
             | infer what you mean you are most likely writing invalid
             | code.
             | 
             | > Error messages like "This expression is of type X but an
             | expression was expected of type X" were not uncommon, and
             | super frustrating.
             | 
             | Ocaml is a strongly typed static language. As such your
             | code has to respect type constraints. It's very much a
             | feature not a bug.
             | 
             | Still to be less defensive I too sometimes wish the error
             | messages were more clear in highlighting why a certain type
             | was expected but at least Ocaml provides tooling to live
             | check the inferred type of any sub-expression while you
             | edit your code.
        
               | pmoriarty wrote:
               | _" you are most likely writing invalid code"_
               | 
               | Of course I'm writing invalid code: that's why I'm
               | getting error messages. The problem is that I'm having
               | trouble understanding why it's invalid. Error messages
               | are supposed to help me here, but quite often they
               | didn't.. they just led to more confusion... especially in
               | complex code, where I needed help and clarity most.
        
               | kragen wrote:
               | > Ocaml is a strongly typed static language. As such your
               | code has to respect type constraints. It's very much a
               | feature not a bug.
               | 
               | That's reasonable if the error message were "This
               | expression is of type X but an expression was expected of
               | type _Y_ ". But the worst error message in the OCaml
               | interactive toplevel is when they're the same. This
               | happened when you defined a new type named X (which,
               | incidentally, must be lowercase), but there were still
               | references to things of the old type X.
               | 
               | I think this has been fixed in recent versions of OCaml.
        
               | skissane wrote:
               | You can get the same thing in Java essentially: two
               | classes with the same name but loaded by different class
               | loaders are incompatible. You'd get errors at runtime
               | that you can't cast X to X. I think they've made the
               | exception messages more helpful in more recent Java
               | versions, but in older versions the errors were very
               | confusing to newbies because they didn't mention the
               | class loader difference which was the actual cause of
               | them
        
               | kragen wrote:
               | In OCaml I think this could only happen with the
               | interpreter (e.g., an interactive toplevel). At least
               | today the compiler complains if you try to define two
               | types with the same name in the same context.
               | 
               | The problem is that it would happen _often_ in the
               | interpreter when you were interactively trying stuff out,
               | because when you 're trying stuff out, you change the
               | definitions of things.
               | 
               | Python actually sort of has the same problem not only
               | when you use an interactive interpreter but even when you
               | reload a module: the new class definitions don't modify
               | the old one, they just get bound to the same name. So
               | it's easy to end up with two alglayout.Vbox classes or
               | two diff.Formula classes in the same interactive
               | interpreter at the same time. But it's much less of a
               | problem in Python because Python usually doesn't care
               | what class things are, just what methods they define, so
               | objects belonging to both classes can coexist peacefully.
               | The usual exception is when you have an isinstance check
               | somewhere.
        
               | poorlydefined wrote:
               | Yeah if you did this now you'd get something like "this
               | expression is of type t/1 but an expression of type t/2"
               | to disambiguate.
        
               | kragen wrote:
               | The fact that this problem took 25 years to fix is maybe
               | the more damning thing. It wasn't a _bug_ , exactly; it
               | was a usability problem. Clearer demonstrations of
               | development priorities could hardly be given.
        
               | octachron wrote:
               | That was mostly a man-power issue. The good news is that
               | nowadays such nonsensical error messages are near the top
               | of my personal development priority for OCaml.
        
               | kragen wrote:
               | During those 25 years OCaml gained native-code compilers
               | for new architectures, labeled arguments, and polymorphic
               | variants, among other things. How could it be mostly a
               | manpower issue?
        
               | octachron wrote:
               | Work and time contributed by open source collaborators on
               | their free or academic time cannot be magically converted
               | from one subsystem to another. It is honestly very easy
               | to have progress on the aspects that spark interest while
               | some subsystem are starved from attention when there are
               | no full-time developers working on a project.
        
               | kragen wrote:
               | That's true, but that doesn't mean there was no manpower
               | to fix that error message; it meant that fixing it wasn't
               | a priority to the people who were working on OCaml at the
               | time. You're just offering an explanation for _why_ it
               | wasn 't a priority: fixing it didn't spark their
               | interest.
        
               | octachron wrote:
               | And the REPL should warn you that if you have a value of
               | type "t/n" it is probably a left-over from a previous
               | definition of type t in the session.
        
         | mhitza wrote:
         | I guess inscrutable error messages are a "feature" of ML-like
         | languages. I have not used OCaml yet, but the first few years
         | with Haskell probably have been just as rough in terms of
         | parsing type errors.
         | 
         | Haskell has a few niceties when trying to debug type errors
         | nowadays. For example typed holes that allows one to spice in
         | `_` within code and the compiler will tell you what type it
         | expects you to replace that hole with, alleviating many issues
         | I had previously. But in the same sense I'm in agreement with
         | you, and I've been more productive when writing Guile/Chicken
         | Scheme code for small tools.
         | 
         | Interestingly I've binged on OCaml videos recently, because I
         | would find it interesting to work with it some day. From a
         | distance what I like about it (aside from the functional
         | language goodness) is that it supports objects, has row
         | polymorphism, optional arguments, and imperative constructs (I
         | sure like my mutation heavy for/while loops when prototyping
         | code).
        
         | bmitc wrote:
         | I haven't actually used OCaml in any depth, but I have found
         | that F# tends to have quite good error messages. In the
         | _Programming Languages_ Coursera course, I found that SML has
         | pretty bad error messages.
        
       | baby wrote:
       | shameless plug: learn with ocaml by example[1]. It is still
       | heavily work in progress though, please feel free to create a PR
       | :)
       | 
       | [1]: https://o1-labs.github.io/ocamlbyexample/
        
       | dgan wrote:
       | TIL that Ocaml/SML are compiled into lambda expressions... I
       | literally thought lambda calculus is only used in CS classes.
       | 
       | OCaml's syntax is pretty annoying but type inference is actually
       | amazing.. I changed my mind over it, as previously I thought
       | explicit type annotations are simpler. Turns out, it would be
       | humanly impossible to explicitly annotate every piece of OCaml,
       | just let the compiler do it for you
        
         | eatonphil wrote:
         | Did you learn that from some other article? I couldn't find
         | "lambda" in this page.
         | 
         | I think it's too much to say that all Standard ML compilers
         | work or one way or another. There are 6 major compilers and a
         | number of minor ones.
         | 
         | They don't really follow the same approaches in general.
        
           | octachron wrote:
           | One of the intermediary representation used by the OCaml
           | compiler is a lambda calculus (https://github.com/ocaml/ocaml
           | /blob/trunk/lambda/lambda.mli#...). But yes, this is only the
           | OCaml compiler.
        
           | frou_dh wrote:
           | At a higher level that that, it's cool that even in SML's
           | already sparse surface-level syntax, quite of a bit of it is
           | just sugar for each other: https://i.imgur.com/pkSg4xm.png
        
             | eatonphil wrote:
             | That may be the semantics of it and for simple compilers
             | that may be a true transform. But as compilers get more
             | mature they tend to specialize everywhere they can so the
             | actual compiler doing this under the hood may or may not
             | happen.
        
         | kryptiskt wrote:
         | GHC's Core language is amazingly small https://gitlab.haskell.o
         | rg/ghc/ghc/-/wikis/commentary/compil..., and it's just
         | polymorphic lambda calculus (with coercions added a while ago).
        
         | giraffe_lady wrote:
         | What do you not like about the syntax? I hear this often, and I
         | vaguely remember not liking it myself at one point. But it was
         | also my first ML and now I can't remember what specifically I
         | found unpleasant.
         | 
         | I do think I've partially ascended into senior dev galaxy brain
         | around syntax though. For the most part I think they're all
         | fine and also all bad and also don't matter very much at all.
        
       | bmc7505 wrote:
       | ML really is a beautiful and under-appreciated family of
       | languages. Haskell is a bit too supernatural for my taste, but ML
       | and its derivatives hit the sweet spot between powerful type
       | systems and natural syntax. As a Kotlin developer, I find reading
       | OCaml code a breeze and the compiler is refreshingly snappy (much
       | faster than Gradle). I just wish it had better developer tools.
        
         | throwaway894345 wrote:
         | I like Rust for syntax, tooling, and ML ideas but I wish there
         | was a "Rust-lite" that was garbage collected.
        
           | gcr wrote:
           | how do you feel about nim?
        
             | throwaway894345 wrote:
             | Haven't looked much at it yet.
        
           | maficious wrote:
           | Gleam
        
             | throwaway894345 wrote:
             | Yeah, this is one I'm keeping my eye on.
        
           | ChadNauseam wrote:
           | It's got its warts, but Ocaml (and ReasonML if you want a
           | more familiar syntax) are right in that sweet spot for me.
        
             | throwaway894345 wrote:
             | I need to give ReasonML another shot. It's been a few
             | years, but at the time it really only seemed to work if you
             | were targeting BuckleScript and even then you had to write
             | a bunch of Makefiles and jump through other weird hoops.
             | Beyond that, it suffered from some other OCaml issues--
             | multiple "standard" libraries, different packages using
             | different async libraries, some gratuitously abstract
             | libraries, etc.
             | 
             | I'm really hoping it breaks into the mainstream such that
             | it gets the investment that other mainstream languages get
             | (hopefully said investment will smooth out these rough
             | edges).
        
           | gpderetta wrote:
           | with its shared-nothing-by-default thread model, rust would
           | make for an excellent GC'd language as if it gave the ability
           | of opting into GC on a per-thread basis with thread local
           | heap and GC. Some relaxing of the shared-xor-mutable probably
           | would need to be relaxed though.
           | 
           | I don't know how practical it would be to implement in
           | practice.
        
           | Serow225 wrote:
           | that's pretty much F# :)
        
             | mumblemumble wrote:
             | As a long-time F# user and current Rust learner, I would
             | say the similarities are mostly cosmetic.
             | 
             | First and foremost, F# is functional-first, while Rust
             | isn't really functional. Rust takes some useful features
             | from functional languages, to be sure, but the overall
             | paradigm is more procedural. A lot of key functional idioms
             | and design patterns don't really fly in Rust because it's
             | difficult-to-impossible to make them play nice with its
             | memory management model.
             | 
             | Rust has traits, but not OOP. F# has OOP but not traits or
             | typeclasses.
             | 
             | F# is immutable by default, and discourages mutability.
             | Rust is immutable by default, but embraces (and tames)
             | mutability.
        
             | throwaway894345 wrote:
             | If F# had static, native compilation by default, a closer
             | Cargo analog, and eschewed the OO stuff (probably mostly
             | just there for C# interop?) and the OCaml syntax.
        
         | bmitc wrote:
         | I fully agree. F# is my favorite language, and it almost feels
         | like a statically typed Scheme at times, just with built-in
         | pattern matching and pipes thrown in. It's a really great way
         | to program, and it's easy to go imperative or OOP when needed
         | without friction.
         | 
         | The only thing missing from F# is an Elixir/Erlang/OTP-like
         | process system (`MailboxProcessor` is pretty good though), but
         | then again, every language except Elixir/Erlang/OTP is missing
         | that.
        
           | lf-non wrote:
           | I am not further enough in my F# journey to have tried this,
           | but you could technically pair it with orleans for actor
           | oriented systems ?
           | 
           | Love the language though I have spent only a week working
           | with it. It seems to have a lot of things I liked in Kotlin.
        
             | bmitc wrote:
             | F# does have the `MailboxProcessor`. It is quite simple and
             | capable.
             | 
             | https://fsharp.github.io/fsharp-core-
             | docs/reference/fsharp-c...
             | 
             | https://fsharpforfunandprofit.com/posts/concurrency-actor-
             | mo...
             | 
             | I haven't looked at Orleans in a while. Last time I did, I
             | came away with the viewpoint that it was very much designed
             | to have a C# interface, which while manageable in F#,
             | doesn't really provide for an idiomatic F# experience. I'm
             | also not too sure, but I think it basically requires a
             | cloud or distributed environment. Can it just be run on a
             | local computer?
             | 
             | But even the `MailboxProcessor` doesn't do what Elixir and
             | Erlang do on top of the BEAM VM. An instance of a BEAM VM
             | is a single OS process, but the BEAM can handle millions of
             | Erlang processes, which are not OS processes or even
             | threads. They are their own thing that are extremely
             | lightweight. The BEAM scheduler is very nice as well, such
             | that it switches among all the running processes.
             | 
             | Even though I develop in Elixir, I am not yet a BEAM
             | expert. So before I say something incorrect, I recommend
             | taking a look at the talk _The Soul of Erlang and Elixir_
             | by Sasa Juric.
             | 
             | https://www.youtube.com/watch?v=JvBT4XBdoUE
             | 
             | It fully encapsulates and describes what makes processes so
             | special in Elixir and Erlang.
             | 
             | There is the Gleam language, which is a statically typed
             | language on the BEAM VM. However, they moved away from the
             | ML-dialect syntax, which is unfortunate.
        
               | cassepipe wrote:
               | ... and also Caramel which is a Ocaml/Reason dialect so
               | you get to keep the Ocaml syntax
               | 
               | I have never tried it though
               | 
               | https://caramel.run/manual/introduction.html
        
               | pharmakom wrote:
               | Maybe one day Fable will add an Erlang backend.
        
       | shikoba wrote:
       | The golden rule is missing:
       | 
       | > Don't try to understand the error message except if you have no
       | other choice.
        
       | pharmakom wrote:
       | A good list. ML languages push you (kicking and screaming) into
       | the pit of success.
        
         | bmitc wrote:
         | Kicking and screaming? ML dialects, or at least F#, are usually
         | a pleasure.
        
         | nnoitra wrote:
         | They're barely used in industry.
        
           | asplake wrote:
           | But look at their influence: TypeScript and Rust, not to
           | mention Elm, PureScript and other less mainstream languages
        
             | darksaints wrote:
             | + Scala
        
             | tgv wrote:
             | TypeScript is very much a C++ descedant, IMO.
        
           | marginalia_nu wrote:
           | Even if functional programming itself isn't used, a lot of
           | its patterns are extremely useful even outside of functional
           | programming.
           | 
           | Code returning side effects rather than _having_ side
           | effects, for example, is great, and I find myself returning
           | to the principle in a lot of the stuff I design as an
           | architectural principle.
        
           | gpderetta wrote:
           | I wonder why this is the case. Ocaml syntax doesn't seem very
           | arcane, it is not hell-bent on functional purism and
           | pragmatically allows for imperative code. Performance seems
           | quite reasonable.
           | 
           | What does it lack that prevented it from gaining wider
           | acceptance? Surely buy-in from a large company was an issue,
           | but even F# hasn't seen any significant uptake. Is it really
           | the lack of curly brackets? That didn't stop Python...
           | 
           | Is it just that being labelled 'functional' was a huge stigma
           | for a very long time?
        
             | dgan wrote:
             | Libraries!!! Python is "batteries included" while OCaml
             | barely has insulation around electrical wires. EDIT: okey
             | that actually maight be a chicken-egg reasonning
        
             | WastingMyTime89 wrote:
             | If Ocaml had been designed in the USA it would have been
             | widely successful. It's main drawback was being mostly a
             | French project.
        
               | usrnm wrote:
               | > If Ocaml had been designed in the USA it would have
               | been widely successful
               | 
               | I doubt that. There are plenty of American SML dialects
               | and F# is about as American as it gets, but neither of
               | these languages saw any commercial success.
        
             | kragen wrote:
             | The syntax is not great, the standard library is very
             | sparse, and the error messages from the compiler and
             | interpreter are terrible (and used to be worse). The OCaml
             | team used to treat the native code compiler (ocamlopt) as a
             | second-class citizen, but it's the implementation that
             | matters for performance. Since the end of Dennard scaling
             | about 15 years ago, OCaml's lack of multithreading has also
             | been a pain point, one which is finally starting to improve
             | in the last year or two.
             | 
             | I don't think being labeled "functional" was ever a huge
             | stigma. Being labeled "Haskell" is a huge stigma in some
             | circles, but OCaml's never been labeled "Haskell". Until
             | about 10 years ago functional programming didn't become
             | popular enough to have any kind of popular opinion,
             | positive or negative, and the people who knew about it
             | generally thought it would be nice to do more of it.
             | 
             | Mostly I think people use a programming language either
             | because they already know it or it's the scripting language
             | for an environment they have to use. Assembly was the
             | scripting language for your CPU, especially in mainframe
             | days. BASIC was the scripting language for personal
             | computers. Visual Basic was the scripting language for
             | WIMPs. VBA was the scripting language for Excel and Word
             | (previously Excel had a table-based macro thing). sh was
             | the scripting language for the Unix filesystem; C was the
             | scripting language for the Unix system call interface, and
             | a nice upgrade from assembly. JS was and is the scripting
             | language for the browser. Lua is the scripting language for
             | WoW, Roblox, and Minetest. Perl was the scripting language
             | of the WWW, then PHP was, or Ruby if what you really want
             | to script is Rails. SQL is the scripting language for your
             | database. Objective-C was the scripting language for
             | NeXTStep; now Swift is. MATLAB was the scripting language
             | for EISPACK and later *PACK and BLAS, though it had some
             | competition from IDL for a while. Now Python is the
             | scripting language for Numpy (and thus BLAS), Matplotlib,
             | and TensorFlow. Only a few popular languages are exceptions
             | to this rule: Fortran, COBOL, C++, Java, R, Pascal, Golang,
             | and C#.
             | 
             | OCaml? OCaml is the scripting language of ocamlyacc and
             | Coq. If you write OCaml then it's probably because you like
             | Coq. This may have been a public relations problem in the
             | Anglosphere, especially before same-sex marriage.
        
               | bmitc wrote:
               | All those things you mentioned in the first two
               | paragraphs are fixed by F#, however, it is still not
               | popular.
               | 
               | The reasons in that case are that .NET was not originally
               | cross-platform, which was a major blunder for Microsoft,
               | C#, and especially F#. The other is that people have some
               | weird stigma against Microsoft, despite it not applying
               | in many cases. Although they should have started off
               | cross-platform, the transition from .NET Framework, to
               | .NET Core, and now to .NET 5/6/7 has been really
               | impressive. That along with GitHub and Visual Studio
               | Code, it's pretty amazing how much progress Microsoft has
               | made for developers.
               | 
               | I just wish it would bring more people to F#, as it's
               | sort of a Goldilocks language since it hits so many sweet
               | spots.
        
               | kragen wrote:
               | Not being labeled "Haskell" is fixed by F#?
               | 
               | And I don't know that F#'s syntax is better than OCaml's.
               | Arguably it's worse. (I haven't tried using it so I don't
               | know how the error messages are.)
        
               | wawjgreen wrote:
        
               | octachron wrote:
               | Why do you think that the native compiler was treated as
               | a second class citizen? This is quite strange take from
               | my point of view. For instance OCaml native compiler was
               | available on the M1 Macs two months after the M1 release.
               | Similarly, all major CPU architectures (x86, ARM,
               | PowerPC, RISC-V, s390x) have been supported for years.
        
               | kragen wrote:
               | 20 and 25 years ago, the attitude (as I remember it) was
               | that the native-code compiler was not very important
               | because the bytecode interpreter was fast enough for most
               | uses.
               | 
               | It's true that that is no longer the attitude. But if we
               | want to understand why one language is more popular than
               | another, we usually need to look at things that happened
               | in the past, not just things that are happening right
               | now. Even C's meteoric rise took 15 years from the first
               | C compilers until it was the undisputed queen of
               | programming languages, partly as a result of missteps
               | made by the communities of ALGOL-68, ALGOL-W, Lisp, PL/I,
               | SNOBOL, TRAC, FORTRAN, BCPL, and, perhaps most
               | interestingly, MULTICS, 20 years earlier.
               | 
               | (It's also possible that my memory that the OCaml team
               | treated the native-code compiler as a second-class
               | citizen is incorrect, either because I misremember what
               | they were saying or because I misinterpreted it.)
        
               | octachron wrote:
               | Ah yes, it might be possible that during the time of Caml
               | light, the bytecode compiler was for a time considered to
               | be fast enough. I am not sure that a ephemeral stance
               | from 25 years ago on an ancestor language still really
               | matters nowadays.
        
               | kragen wrote:
               | I'm not talking about Caml Light or even Caml Special
               | Light, which is when the native-code compiler was
               | initially added. 25 years ago was 01997. Objective Caml
               | was released in 01996 (and renamed OCaml in 02011).
               | 
               | Projects like KDE, the GIMP, GNOME, Lucene, Jython, LLVM,
               | Asterisk, Audacity, CMake, and Danger that got started in
               | C, C++, or Java in the 01997-02002 period are still based
               | on those languages today. OCaml would have been a
               | reasonable language for all of these, though a new
               | interpreter for Python in OCaml would have lacked
               | Jython's key feature, the ability to easily script _other
               | things_ written in Java.
               | 
               | (Danger? Well, Danger as such ended in 02011, but Andy
               | Rubin founded Danger in 01999 and left to found Android
               | in 02003, which ended up making a Java-based smartphone
               | much like Danger's Java-based smartphone, but less locked
               | down.)
               | 
               | The fact that _Java_ focused _heavily_ on performance
               | starting in 01997, when Sun bought Animorphic, meant that
               | a _lot_ of things were able to be written in Java in the
               | 02000s, things that were previously just unthinkable.
               | Lucene predates HotSpot by a bit, but the whole Hadoop
               | ecosystem that grew out of it only makes sense in a
               | HotSpot world. Minecraft obviously pushes performance
               | heavily. SPARK is written in Scala, but OCaml would have
               | been a good fit too--if Hadoop had gone that direction.
        
               | thingification wrote:
               | I have to ask: you're concerned about the year 9999
               | problem?
        
               | yawaramin wrote:
               | > ...if we want to understand why one language is more
               | popular than another, we usually need to look at things
               | that happened in the past, not just things that are
               | happening right now
               | 
               | Figuring out why OCaml didn't get popular in the past is
               | not a super useful exercise. It's more useful to
               | understand what is needed to popularize it today.
        
               | benibela wrote:
               | Then COBOL would be the scripting language for the
               | mainframe, and C# would be the scripting language for
               | Windows
        
             | chii wrote:
             | It's not that there's stigma, but that it is probably more
             | difficult to think functionally when most programming
             | education teaches imperative methods.
        
       | cassepipe wrote:
       | Could someone please explain ? : type 'a list = 'a :: 'a list |
       | []
       | 
       | The article says "::" is a Data Constructor. I can make sense of
       | type 'a = Left of 'a | Right of 'a where Right and Left are the
       | Data constructors but I don't see the link with the part I don't
       | understand.
        
         | bmitc wrote:
         | `|` is read as "or". `::` is syntax for what Lisp and Scheme
         | call `cons`, which places an element onto either a list or the
         | empty list, `[]`. The syntax `'a` is a type variable, which
         | means that `'a` can be any type but it must all be the same
         | type everywhere `'a` appears.
         | 
         | So this type definition means that `'a list` is a list of
         | elements of type `'a`, and it's defined by being something of
         | type `'a` consed onto either another list of type `'a` OR the
         | empty list, represented by `[]`.
        
         | dan-robertson wrote:
         | The definition of list is:                 type 'a list = [] |
         | (::) of 'a * 'a list
         | 
         | When you write a list like:                 [x; y; z]
         | 
         | This is syntactic sugar for:                 x::y::z::[]
         | 
         | Which is syntactic sugar for:                 (::) (x, (::) (y,
         | (::) (z, [])))
         | 
         | One can imagine using more ordinary constructor names instead:
         | type 'a list = Nil | Cons of 'a * 'a list
         | 
         | And then the above would be:                 Cons (x, Cons (y,
         | Cons (z, Nil)))
         | 
         | In OCaml, data constructor names mar be either a capital letter
         | followed by set or more capital/lower
         | letters/underscores/apostrophes/digits, or one of the
         | following:                 []       ()       true       false
         | (::)
         | 
         | Type directed constructor disambiguating means you can do funky
         | things like:                 type 'a nonempty = (::) of 'a * 'a
         | list
         | 
         | And write such a value just like you would a normal list.
        
           | cassepipe wrote:
           | Thanks for the detailed explanation. One more question
           | though, when I write                   type 'a = 'a :: list
           | 'a
           | 
           | It is syntactic sugar that allows me to get the * product
           | type for free, right ?
        
             | dan-robertson wrote:
             | I think that is made up syntax from the article but maybe
             | I'm wrong.
        
             | yawaramin wrote:
             | That's actually invalid syntax. '::' can't be used infix in
             | a type declaration. And type application is in reverse. So
             | it's not list 'a but 'a list.
        
         | lifthrasiir wrote:
         | It is equivalent to the following:                 type 'a list
         | = Cons of 'a * 'a list | Tail
         | 
         | ...but with a fancy syntax for Cons and Tail.
        
           | cassepipe wrote:
           | Ok. So in your example the construction action (placing two
           | things next to each other IIUC) is done by the * product type
           | Operator and Cons has no special meaning whereas if I had
           | used ::, I actually get an the (::) name to refer to the left
           | hand of the union _and_ the construction action. Did I get
           | that right ?
        
         | maweki wrote:
         | A list is either the empty list [] or
         | 
         | Two pieces of data (with the constructor ::) with 1 being the
         | head of the list (type 'a) and one being the tail of the list
         | (type 'a list, a recursive definition).
         | 
         | :: is an allowed identifier in oCaml. If that is not allowed,
         | the typical names are Cons for :: and Nil for []
        
           | cassepipe wrote:
           | Thanks. I had not understood it could be recursive.
           | 
           | Do you know Cons' meaning ?
           | 
           | Also why does :: act as a separator... ? Is that something
           | you ca do with any Data constructor, I mean can I write type
           | 'a = 'a Cons of 'a | Nil of 'a ?
        
             | maweki wrote:
             | You would write something like List a = Cons a (List a) |
             | Nil
             | 
             | As :: doesn't start with a letter, it's infix by default.
             | But basically a binary constructor. If you want to create
             | the List [1,2,3] in the prefix notation you might be used
             | to: ::(1,::(2,::(3,[])))
        
             | willmorrison wrote:
             | Here is the Wikipedia page:
             | https://en.m.wikipedia.org/wiki/Cons
        
             | gpderetta wrote:
             | Cons comes from Lisp: https://en.wikipedia.org/wiki/Cons .
             | In practice a cons cell is a list node represented as a
             | pair of pointers, one pointing to the contained element,
             | the other to the next node (or null, or another element for
             | degenerate lists).
        
       ___________________________________________________________________
       (page generated 2022-05-03 23:02 UTC)