I discovered Sketch on the OCaml forum just after I finished the alpha version of domical. I'll publish domical after some issues coming from iodide are corrected.
Sketch is really awesome, and serves different purposes. Domical is just an interpreter for the iodide notebooks, which are designed to be portable and execute all kind of languages: js, python (those crazy folks compiled the full interpreter and f numpy in WASM) and now OCaml.
I can see that sketch has really a lot more features.
A key feature of iodide is its simplicity and portability: the whole notebook is written in a readable format looking like markdown and called jsmd. Take a look at the source code of the page to better understand.
So definitely we have a lot to share on our respective projects, even if I am not one of the main contributors of iodide (I just did the OCaml part).
If you want to continue this discussion, my email is on my homepage :)
Of course, I put the "`" to indicate the interpreter command. The compiler is called with `ocamlc`.
The online version is basically a top-level exucuted by the js engine of your browser, and it is more performant than its equivalent executed natively.
What's the current state of OCaml on Windows? I'd love to use OCaml on more of my projects, but this has been a roadblock for me.
What I'm looking for is the ability to produce native binaries without Cygwin. I just checked without installing anything and it appeared as though OCPWin was still the choice, but it's been stuck on OCaml version 4.01.0, which was released five years ago. I know that OPAM is pushing toward a 2.0 release very soon and I didn't know if that was going to coincide with a stable OCaml/OPAM release on Windows, which would fix my problems. Does anyone have an idea?
I'm looking forward to the day when I won't need Cygwin even in the build environment. Since the OCaml compiler itself works fine on Windows and modern build systems like "dune" are also Windows-friendly I'm fairly optimistic this can happen soon. I think it'll mostly be a matter of removing accidental Unix-isms (like unnecessary use of symlinks) in the build scripts.
Mostly, I'd like to ensure that I don't like the dll, so that I don't have to attempt to distribute it. More selfishly, I'd like to have a straightforward installation process where I pull down only a binary or two and can have a working environment and the ability to integrate additional packages.
I didn't know about dune. Looks neat. Is this meant to be used in conjunction with opam?
Yes -- opam and dune are complimentary. I normally use dune (formerly known as "jbuilder") as the build system within my packages, which I then publish and install via opam. Dune does the fast incremental builds, while opam deals with version constraint solving, downloading and general package metadata.
There are some interesting experiments combining the two more closely -- take a look at "duniverse" https://github.com/avsm/duniverse which is a prototype system which would use opam to solve package version constraints and download the sources, allowing dune to build everything at once. The nice thing about this is that you could patch one of your dependencies and then dune will be able to perform an incremental build, as if all the code was in one big project. I'm personally hoping this will help speed up Mirage development as it can be time-consuming to propose a change to an interface and then find all the places that need changing (a cost of having lots of small repos versus a big monorepo)
LexiFi use OCaml on windows in the industrial environment (they even have a .Net integration), so the language is stable. Many packages are working fine on windows too. opam is building already I think, but is not yet stable, you could ask them on github tho. The right way to install ocaml is [1]. I don't think you can avoid cygwin completely since you need rsync and similar stuff for some packages, tho the produced binaries do not require cigwin.
I've thought about it and wrote a bunch of trial software to test things. Primarily, I work on Linux even though I support Windows. There are also some features in OCaml that I like, which are not available on F# such as the module system, polymorphic variants, and, in the past, camlp4. While these can be worked around, the other use case is running the software on an HPC system using MPI. For me, the use of OCaml or F# is a glue, so I'm not worried about the performance. I am a little worried that the HPC administrators are going to have some difficulty getting the correct setup for F# across all the nodes. For OCaml I don't view this as much of a problem since it just produces binaries. Now, I absolutely could be wrong about this and I'd appreciate if someone where to chime in if so.
"Expert F#" by Don Syme et. all. is a great starting point. It explains how to get started and contains lots of non-trivial code to type in and try out yourself. Don Syme designed F# as a no-nonsense industrial language and this book is a great introduction from that point of view.
Then there is "Programming language Concepts" by Sestoft - which, while being a language book, at the same time exposes lot of beautiful patterns how to exactly use F# for data munching.
Then, thirdly, Jon Harrop's "F# for scientist" is a great introduction for us that have a penchant foe writing numerical code (graphics or whatever). It's a great companion for the Expert F# as it shows how to use F# effectively in place of sonething like C++ or fortran.
All nice and dandy, but please, for the sake of everything, can this site just stop auto advancing on steps?!
I click the last one and advance a step before I can comprehend what this command did or read any context.
Breaks flow completely... And I'm just able to be fine advancing manually once I feel I'm done with the current step.
Other nits:
* show the ;; in the step code snippets, at least at the beginning - else you may be confused fast if you hack around in the "terminal"
* add a 'run this snippet now' button to the code snippets, a small green triangle or whatever those IDEs are using nowadays, allows to copy of examples either modifying before execution or - like me - paste them in a "real" OCAML REPL I have on my desktop.
don't get me wrong, the site and idea is nice, those things just irritate me, almost irrationally, from an UX POV.
I know cryptocurrency is contentious in this community so apologies for injecting it here:
OCamlPro is heavily involved in the development of Tezos and a big part of the reason I invested in it. One of the main selling points of Tezos is formal verification, which OCaml (being a pure-ish functional language) was instrumental for.
Regardless of the future of crypto (fad or world changing) if it's handling money or other assets it should be done safely. This is step in that direction.
It was __very__ amusing to play with Variants, Pattern Matching and Units. If programm compiles - it almost always just works.
It's an indispensable tool to play around and get more ideas how to write a better programs.
And it was disastrous in __everything__ else.
Installation and compiler bugs. Terrible tooling. Terrible code packaging. Terrible Javascript interop. Painfully archaic syntax. Sometimes extremely esoteric compiler errors.
After a week i thrown out all the code and rewritten it using Typescript. Won't ever use new languages on projects with deadlines, no matter how sweet evangilists talks are.
I would encourage you to try it again. There were some big changes in ReasonML in the last year.
I've picked up ReasonML about 3 months ago and experienced almost none of the issues you described. It's still a little rough around the edges compared to for example Elm, but the tooling, packaging, Javascript interop etc are really good IMO.
We have built a design-to-code tool (Sketch to clean HTML & CSS) in Reason[1], and it has been the best experience ever in my 10 years of programming.
We even used Reason for writing ObjectiveC/Cocoa through CocoaScript (a Javascript-to-ObjC bridge), thanks to Reason/BuckleScript's excellent Javascript interop.
The language and compiler is rock solid - it has to be because it has been worked on for over 40 years from the days of ML. For the last three years a team of people including Hongbo Zhang, Jordan Walke, Cheng Lou and others have been actively working on Javascript tooling for OCaml, and it is an absolute pleasure to use today.
> If programm compiles - it almost always just works.
I can never understand this claim when people make it about languages like Haskell and ReasonML.
How is the compiler catching your logic bugs? If you write 'a + b' and you should have written 'a - b' the compiler isn't going to catch that in either of those languages. It'll compile but it won't work. Do you never make these kind of logic bugs?
The type system is a lot more expressive than the ones found in Java/C#/C++, thanks to Algebraic Data Types.
Yaron Minsky (Jane Street, largest OCaml user) coined the term "make invalid states unrepresentable" to explain how ADTs help in enlisting the help of the compiler to help us express our intent correctly, and Richard Feldman (NoRedInk, largest Elm user) has given an absolute gem of a talk that dives into that idea with relatable, concrete examples.
I've done a lot of work in Python and a fair amount of ocaml and rust.
I find that in Python - probably any dynamic language - a lot of the tests I write are just to make sure the pieces fit together. It's too easy to write well tested units that don't work together because of a misplaced argument or something at the interface. That type of testing is largely not needed with static typing.
Also, when I create a data structure in Python my mental model of what it means and how it relates to other parts of the program can be kind of fuzzy. Which means the pieces may not fit like I think they do because I missed a detail.
But a strong static type system forces me to clarify my thinking much earlier in the coding process than in a dynamic language. It encourages me to encode more of my mental model into the code and that allows the compiler to double check me.
I believe this claim to have two more narrow meanings:
1) If it compiles, you won't get a "undefined is not a function".
2) If it worked, you changed something and looked at all the places compiler told you to look at, all the code it didn't tell you to look at is very likely to continue to work corrrectly.
(1) is a very convenient feature and easy to advertise, but (2) is what makes people jump around and tell that everyone should use ML: it allows to be not afraid of changing something in the first place.
Data point. I just converted a small app to Elm 0.19. So, that's a real 0.x: breaking API changes all across the standard library. I just repeatedly ran the compiler and jumped to the next error. About an hour for my 1 KLOC app (and Elm code is pretty sparse), seems rather tedious. But! Now it works again, and I believe it to be working just as good as before. Of course there could be some new bugs, but I would rather expect them in the substantially changed parts of the Elm runtime than in my app where I didn't look at anything compiler didn't tell me to look at.
I have even less experience with OCaml, but my gut feeling is that it should be about the same in this respect unless you let mutable state run wild.
There is a phrase from Yaron Minsky about OCaml, “make illegal states unrepresentable”, which summarize this.
It's more about programming declaratively, functional, as well as strong types which allow you to be very expressive. My experience with F# is similar, if you can get you code compiled, it almost always just works as you expect. But this doesn't mean that you can avoid writing tests though.
Out of curiosity, what are you considering modern?
The trend I see growing is towards microframeworks, smaller libraries, less dependencies (or if you have some, a small opinionated set of them), are more doing it yourself -- I think this phenomena, more simply put and was championed by go -- is to "just write code"
I am enjoying "just writing code" far more than my days as a library and framework glue person, and it is a lot easier to have other devs ramp up, as an added bonus. "Here, read this simple code to understand what's going on and then add your code" versus "here, study these docs, learn this framework, install all these dependencies then learn our coding style within the framework to understand what's going on, then add your code"
I think this something that needs to be experienced firsthand a few times for this to sink in. It something like the backpropagation update of a neural network: no matter how long you stare at it, it wont be clear, but if you derive it yourself it becomes super clear.
I can say that this effect seems very real. I think the reason goes beyond those shallow type mismatch errors I often make. Part of the reason, I think is, the correct program becomes clearer to write compared to the erroneous programs you could have written if you use the type system. In other words types can make some of the erroneous versions cumbersome, or at time, impossible to write -- but good luck mud wrestling with the compiler till its convinced.
I will strongly encourage that you try it and dont be discouraged. This really needs to be experienced first hand to be convinced.
The more meaning you can encode in the type system, the more the compiler can help you.
It won't help you catch a + b... unless you e.g. declared a to be of type meters, and b inches.
I think that statement is better viewed in lights of refactoring or changing existing code.
If the code worked/compiled before, and I made a change that still compiles, I can be reasonably confident it didn't break something else accidentally (assuming the program was reasonably well designed to begin with).
It makes reviewing pull-requests much easier.
Doing so in other programming languages always makes me nervous, in C an innocuous change could introduce some memory corruption bug because you broke an implicit invariant of the code, in Python it could raise a type error when called in an unexpected way.
To review a pull-request you have to look usually at the entire file (or sometimes the entire project), and even then you can't be sure.
As for the logic bugs: that is what tests are for.
The compiler does not catch your logic bugs. But stronger, more expressive type systems catch syntax bugs and structural errors like you wouldn't believe. It's not an all or nothing.
I have spent an embarrassing amount of time troubleshooting a < that should have been a > (in F#) where it actually resulted in a very subtle defect. I'm not aware of a type system that works have prevented this and yet,I do strongly agree with the assertion that in more strongly/statically typed language, "compiling successfully = very likely to run correctly."
It kind of applies to those languages. It more applies to languages like SPARK or Eiffel. But yeah like other posters have said, it's more about avoiding runtime errors.
It doesn't, and I agree with your sentiment. IIRC, type-related errors account for ~10% of bugs.
If (and only if) types are tied into your tooling ecosystem (for example, an IDEs that uses that info to full extent to aid in code completion, refactoring, code analysis etc.), they are very useful.
This sounds implausible to me unless they're only counting bugs that have slipped through QA and have later been fixed in production. In my experience the compiler catches maybe 95% of my errors I write. Most of those would be caught by my unit tests or my manual testing, and a few more would be caught by the QA team, but it's much nicer and faster to get notified about them immediately.
> It doesn't, and I agree with your sentiment. IIRC, type-related errors account for ~10% of bugs.
I never thought of that, but that is a really valid point. I guess that is why Ruby/Python are so popular as most of the problems programmers run into in production aren't type problems.
Type correctness is pure power, or a waste of time, depending on... perspective! I can't help thinking back to the highly illustrative example of my first enhancement to Facebook's production website as a "bootcamper" in 2009.
I was tasked with adding proper honorifics for Japanese speakers (it's complicated in the general case, but I was just getting as far as "San"). I wrote some straightforward PHP code to implement this feature, but of course it broke in production for some nontrivial percentage of requests. Why? Because the string I was adding the honorific to wasn't always a string. WTF? What is the proper course of action when strings aren't strings? Well, in this case the answer was a run-time type-check guard on the code I had added.
Keith Adams, my esteemed colleague, likened this to "dogs and cats living together", perhaps revealing a fondness for simpler days when Ghostbusters trod the streets. Keith may not have gone as far as lauding OCaml's type system in those dark early days, but I will do so now (and perhaps he would too).
That is not why these languages are popular. Types are your design document in languages with expressive type system. So by design you can make it hard to make logical errors.
You might want to try Rust. It has a lot of the ML niceties but with a modern syntax and pretty good tooling. I wouldn't recommend anything other than JavaScript/TypeScript for frontend stuff though.
I am writing Rust more or less daily for my research code (in machine learning & natural language processing), but be prepared to implement a lot of functionality yourself or bind C libraries. The numerical computing/machine learning ecosystem is still very young/small on Rust.
have you talked/written about this in a longer form anywhere? I'd love to read how you got into this if so.
There's plenty of Rust-talk here on HN, and plenty of numerical/ML talk, but they seems like very non-overlapping user groups. Particularly curious why you chose Rust over Julia or even Go, given that (to an outsider) both seem to have a lot more people excited to do ML with them.
I currently don't really have time currently to write this up in a blog post or article. As the state of the field is, it is often handy to be able to bind to C or C++ libraries (such as liblinear, Tensorflow, etc.).
I used to use Go when Rust 1.0 was not out yet. I was generally happy with Go. My primary gripes were:
(1) C calls are relatively expensive, which is ok for long-running functions (e.g. run a Tensorflow session), but now nice for calling C code in a tight loop.
(2) Go gives no control over memory alignment, while C++ machine learning libraries generally prefer alignment on a certain boundary. IIRC Go aligns slices on a 16-byte boundary and Eigen (which is used on Tensorflow) wants arrays that are aligned on a 32-bit boundary. I don't know if this is still true, but Tensorflow used to make a copy of an array that was incorrectly aligned. So, you had to resort to doing allocation in C and then using the SliceHeader hack to give the array somewhat of a native Go interface. But since the backing memory is allocated in C-land and Go does not have general destructors (only defer), you have to rely on finalizers to do deallocation (which provide no guarantee when they are called) and/or relying on the user to explicitly call a resource deallocation method. Of course, that does not really gel well with slices.
(3) Rust + LLVM optimizes far better than the Go compiler. This is not a secret. Parametric polymorphism provides much more opportunities for inlining than dynamic dispatch and LLVM inlines and optimizes aggressively. I spent a lot of time compiling compiled Rust and compiled Go assembly and the differences are quite shocking. That said, the Go people have been working on better inlining as of recently and with the possibility of generic in Go 2.0, things will probably get better.
That said, I think that in larger teams, Go may still be the better choice. It is easier to pick up. It is harder to make code that is 'too clever'. It has good packages, such as gonum, which provides a lot of linear algebra functionality and functionality for plotting. Tensorflow has direct support for Go, including for building computation graphs, etc.
I would love to try Julia! But I did not progress much beyond the first few steps of the tutorial ;). I think I would like it much for quick exploration in the vain of Python + numpy.
We do have people interested, but it's not a ton so far.
One big reason that numerics aren't the best in Rust right now is the lack of integer generics. Some people are waiting for that before bothering to write libraries, as they'd change the libraries so much anyways.
> I wouldn't recommend anything other than JavaScript/TypeScript for frontend stuff though.
My assumption was that anything else would be painful, but I tried some ScalaJS after one too many frustrations with TypeScript and was pleasantly surprised at how easy it all was.
I just finished a ReasonReact project which I started about 3 month ago and I found the experience quite nice (working with VSCode). ReasonML is still in an early stage, but I prefer it over JS/TS for React frontends. The language is a great fit for React. The only thing that I was missing was the amount of Q&A that I'm used to from JS/TS.
Haskell and OCaml try their best to not be popular. Elm is very beginner friendly, docs, installation, great libs for each purpose and is like 5 years old. OCaml has more than 20 years old and for a beginner to install everything and make a REST API is a pain. Why that happens?
>OCaml has more than 20 years old and for a beginner to install everything and make a REST API is a pain. Why that happens?
Nowadays things are quite neat with opam/dune/odig stuff. You can install packages, generate readable docs for them, just like in rust. For the rest api you could just take any existing framework, I think, e.g. [1] [2].
You should also consider that OCaml is a language, which for a long time was intended for a different kind of projects (yeah, webdev is not the only programming domain, shocking), so the direction was dictated by Coq and similar project devs rather then webdevs. Now facebook and other companies change the state of affairs.
I am usually not one for dismissing a language for syntax alone, but, the syntax for arrays versus lists feels very cumbersome. Can an experienced OCaml developer tell me how common it is to use lists versus arrays?
I can only imagine how many bugs I would type at this stage of my career after being used to [] for arrays but forgetting the pipe, and getting a list instead. It's also very difficult to type.
> I can only imagine how many bugs I would type at this stage of my career after being used to [] for arrays but forgetting the pipe, and getting a list instead.
Luckily, the compiler would catch this anywhere you tried to use a list where an array was expected.
> how common it is to use lists versus arrays?
Lists are far more common in day-to-day usage. The language even has native syntax for list consing and destructuring, which is useful for pattern matching.
OCaml arrays do have their place though, if you have a fixed number of items and need random access. Float arrays are also specialized, their elements are unboxed and contiguous which helps with performance for certain types of number-crunching applications.
I was thinking quite the opposite, I admit I don't know much about OCaml yet but I was very interested in trying ReasonML. Anyways, I would think you would use an array when you need sequential access and potentially help locality of reference when doing some number crunching? OCaml arrays are random access?
> you would use an array when you need sequential access and potentially help locality of reference when doing some number crunching
Yes, that's what float arrays were specialized for. From a quick glance at the OCaml compiler code, you might also get effective locality with other unboxed types (ints, chars). Boxed types will likely require an additional lookup even if the values are allocated contiguously. But if you're at the point of being concerned with memory access patterns, then bigarrays will probably work better.
If all you need is sequential access, then a list is much more convenient to use.
I'm not sure how all this translates to ReasonML though, as the JS runtime is very different.
Well, any bugs you would get are very immediate (due to the strong static typing). As for your other point, lists are fairly rare. You only need arrays when you need arbitrary indexing into a list. Most of the time, however, you're simply iterating through the list in some fashion.
When I was learning OCAML and bought the book, Jon actually found some code I had posted on my website and sent me some advice about how to make it more idiomatic. He even rewrote the first one of my functions to show me how.
That book is ancient, but probably still pretty relevant. John Harrop himself posted on reddit awhile back that he hadn't personally used OCaml in a long time when someone asked about the book on the OCaml sub reddit. His username starts with jdh I think. Honestly though, scientific computing seems to be going Julia. Really good numeric, optimization, charting, linear algebra, parallel & distributed computing...etc. It's all free and open source. Julia Computing was founded to provide enterprise support and services including auditing and affordable cloud computing. This is the direction I'm moving towards. You should check out the case studies on Julia Computing.
> Honestly though, scientific computing seems to be going Julia.
I think that the days where one language gets momentum and becomes "the" language for some scientific computing task are gone. No doubt Julia does have momentum. However, these days interoperability is rapidly improving, and we are rapidly moving to an equilibrium where you can more or less choose your own language and not worry too much about it being the "right" language, because you can call libraries written in numerous other languages. I certainly hope that's where we're going.
I work professionally as an applied mathematician and I've struggled to understand where Julia fits into the tools already available.
In terms of prototyping algorithms, MATLAB/Octave still seems to be the best choice. We have access to an enormous number of builtin routines that help diagnose what's going on when an algorithm breaks. That's not to say other language don't, but the ability to set a single dbstop command and then run some kind of diagnostic like plotting the distribution of eigenvalues with d=eig(A); plot(real(d),imag(d),'x') is amazing and saves time. There's also a very straightforward workflow to run the debugger and then drop into gdb in case the case we need to interact with external libraries.
Now, certainly, MATLAB/Octave is weak, in my opinion, for generating larger software projects that need to interact with the rest of the world. This includes things like network connections, GUIs, database access, etc. Alternatively, sometimes a new low level driver needs to be written, which needs to be very fast. All that same, that ecosystem seems to be much better in languages like C++ and Python. Though, I've been experimenting with Rust as an alternative to C++ for this use case. At this point, if I have trouble with the algorithms, I can run it in parallel with the MATLAB/Octave to diagnose how things differ.
Coming back to Julia, where is it supposed to fit in? To me, there's a better prototyping language, production language, and bare metal fast language.
I will make one last quip and that's the licensing. Frankly, the big advantage of MATLAB is that it provides license cover. Mathworks has obtained the appropriate licenses for your expensive factorizations and sparse matrix methodology. Julia has not and they remain largely under GPL:
Look at things like SUITESPARSE. Practically, what that means is that I can deliver MATLAB code to my clients and I don't have to disclose the source externally due to GPL requirements. Now, maybe they choose to run Octave. That's fine and then they can assume the responsibility for GPL code. However, for me, I maintain a MATLAB license and that gives me coverage for a whole host of other licenses in the context of MATLAB code and that makes my life vastly easier than if I were to develop and deliver code in another language.
The beauty of Julia is in its design as a language. This is what gives people hope that the tooling and ecosystem will emerge -- they all seem easier to develop in Julia than in other languages, thanks to multiple dispatch, the type system, and powerful metaprogramming abilities.
As far as fast bare metal languages go, you can write extremely general optimized matrix multiplication libraries in Julia. For matrices that fit in the L2 cache, I achieved performance similar to Intel MKL, but with far more generic code.
Writing a kernel in C means using SIMD intrinsics, where function names and types differ for every vector size, and then different numbers/sets of calls for each kernel (you'd want several sizes per architecture). Compare this to Julia, where parametric typing and multiple dispatch mean you only need one set of functions, and using an @generated function will generate whatever kernels you happen to need at compile time.
Looking into the future, awesome projects like Cassete speak to the potential of what's possible:
Cassete promises to let you do anything from getting automatic differentiation for arbitrary Julia code, even if it is strictly typed and buried in a chain of dependencies of the library you're using and written by someone who never imagined the idea of autodiff, to injecting custom compiler passes.
Julia is more promise than practice right now, but that's largely because of just how much it promises. I (and many others) think it has done a great job delivering so far.
That's why there's excitement, and why many are starting to embrace it.
> Writing a kernel in C means using SIMD intrinsics, where function names and types differ for every vector size, and then different numbers/sets of calls for each kernel (you'd want several sizes per architecture)
This is not true for any recent, competent compiler. I can write a template function in C++ code with a regular loop over arrays and it gets vectorized withSIMD instructions automatically according to architecture. Sure, it’s not JIT but it still never requires intrinsics
> This is not true for any recent, competent compiler. I can write a template function in C++ code with a regular loop over arrays and it gets vectorized withSIMD instructions automatically according to architecture. Sure, it’s not JIT but it still never requires intrinsics
The relevant comparison here is against matlab. If you want to spend two weeks writing and debugging an optimized version of matrix mult for a custom type in c/c++, that's your business, but one can do it in a day in julia and be fairly confident it will just work.
The problem isn't just whether or not it uses SIMD instructions, but avoiding redundant and unnecessary `vmov` instructions. For example, I filed a bug here:
because unless I use SIMD intrinsics, while the code is vectorized, there is a high density of unnecessary move instructions resulting in dramatically slower code.
It can make static libraries. There are some old blog posts on how it can be done. No one has packaged it up though, and it will always be limited to chosen specializations of course.
Use a container. I recommend singularity, works great with julia. Shipped a single binary, deployed on a supercompute center, ran 20 batches over 500 nodes, 16 cores per node, no problem.
Then you are constructing a problem specifically for julia to fail. Congratulations on being a jerk that doesn't pose a question that is relevant to anyone's real use case.
Counter question: Can you in 24 hours ship a binary library built in C or C++ that in guaranteed to work on ARM, x86, and also detect NVIDIA or AMD GPUs and use those for acceleration as needed?
MATLAB, Python, and R don't have the metaprogramming tools for code generation. Tools like FFTW relied heavily on code generation, and people who wrote those kinds of tools are now using Julia for generic programming. Generic programming is difficult to handle with any AOT compilation system since you get a combinatoric explosion of possibilities leading to large compile times. Generic programming works great in Julia so there's a lot of examples of utilizing types for "free features" that would be difficult to do (interactively) in any other language.
Of course, most programmers don't know what generic programming even is. However, a lot of libraries these days utilize it in order to get different precision and all of that, which is why I think Julia will at least become a language of libraries since not too many people can invest so much time in C++.
> most programmers don't know what generic programming even is.
Where do you get this from? You’re coming off far too aggressive. Metaclasses or AST rewriting decorators are parts of Python. I know they don’t fit your use case but you don’t need to set fire to multiple ecosystems because they don’t invoke a full blown compiler for every line of code.
>Generic programming is difficult to handle with any AOT compilation system since you get a combinatoric explosion of possibilities leading to large compile times.
I thought it was either solved by adding function signatures based on actual usage, or “boxing” the argument (which I guess is just dynamic at that point)
Why would you ever see the combinatoric explosion in an AOT implementation?
If you want to make it as a standard library so it can compile once and others link to it, then you have this issue. You need to compile on use in order to only add the function signatures based on use, so if you're doing this from types the user is giving you (say, a generic differential equation solver where the state can be any type with the right overloads) then you're out of luck. If you know of a big set of types the user might want to give you, then you can compile those ahead of time, but for the diffeq example you can have different types for the dependent and independent variable, so you'd want each combination. The solution here of course is just to make people statically compile against it if you want to use all of these features, but you need to compile as a shared library if you want to build an easy interface to a high level scripting language (Julia, Python, R, MATLAB, etc.). So what tends to happen is that libraries which do make some extra features possible are constrained when used from a scripting language and they compile a bunch of choices to mitigate that a bit (see SUNDIALS and its built-in NVector compilations). The true solution here of course is to compile on demand based on the new types you see from the user codes, and this is what Julia does automatically.
As for boxing, boxing works but it's slow. The developer of LightGraphs.jl tried using Swift for awhile but went back to Julia when he realized that actually using generics in Swift is really really slow because they do this boxing (your code is generic! But...). To finish the story, he tried Go a bit but generics in Go... he went to C++ but templates but they were difficult to use and the compile times were too long to be anything close to interactive, and has done extremely well over the last few years in Julia (though it is admittedly missing some tools for (partial) AOT compilation and building binaries, but these tools are in development).
If you want another example, I saw this a couple days ago:
"Also exciting - we only have 27k signatures right now, and removing all the ones taking row vectors reduces that substantially to under 10k. That seems doable pretty easily, and we can convert without performance penalty between row and column vector seamlessly (I believe)."
Those sound like big numbers to me! That's a real problem that DynamicHMC.jl doesn't have to worry about, for example.
I think Stan's autodiff is faster than ForwardDiff.jl/ReverseDiff.jl (other than Stan models regularly taking several minutes to compile), but I'm betting on Cassette-powered Capstan/Zygote getting there in the next few years.
Julia combines rapid prototyping with a well designed language and good execution speed. Matlab only has the first of those three. Julia can plot eigenvalues no problem. Almost exactly the same code works.
The MATLAB compiler is another part of the ecosystem which is worth its price when trying to deliver quickly. There’s nothing like it in the other ecosystems (maybe Mathematica?)
Entire MATLAB toolchain is a ridiculously overpriced relic, the faster it disappears the better, and it will. To a close approximation the only folks who continue to use it are those who are insulated from the market -- national labs, and universities. It annoys me because at places its a ridiculous waste of tax payer's money.
No it's not. I've seen it used within petrochem and other engineering firms as well. For example, the real time simulator Opal-RT uses Simulink and Opals are used for things like simulating power systems.
Although you may not like it, it serves a purpose and it's one tool among many.
I actually work in power systems simulations and am not aware of anyone using the power systems toolbox in Matlab outside of some academic researchers. I'm sure some folks do, but it isn't very big. This is all mainly traditional Fortran and increasingly C++ and even C. There are some open source things like MatPower (Matlab or Python), but it is mostly seen as a neat toy and not something I would trust to actually run grid studies such as an EMS vendor, PSS/E, PowerWorld, Powergem, PSCAD...etc etc etc. I've actually seen that some vendors are looking at Julia to replace some of their tools.
When you say real time, you really mean an EMS system. These have traditional powerflow applications that use something like the Newton-Raphson method, SCADA applications that bring in data from equipment in the field (~4 second data), state-estimator applications that combine traditional powerflow with weighting from the SCADA data, and a Contingency Analysis (does N-1 loss of equipment simulations). Those are the core apps and the US has several vendors ranging from Siemens, Alstom (now GE), GE, OSI...etc.
In power system planning people use PSS/E, PowerWorld, PowerGem TARA, and a variety of other loadflow tools for powerflow and N-1. They don't generally use much real time data and instead use models ranging from 1 year to 20 years in the future. There are also another dozen vendors here selling specialized products that do everything from Voltage Stability to Transient Stability to optimization of topology and fault analysis. The breadth is very wide. You might use multiple vendors with some degree of product overlap because you like vendor A's powerflow functionality and graphics, while vendor B has the best dynamics on the market.
I'll have to check out the links you've sent as I've never heard of these two products and I try to keep my ear to the ground, but it is a huge software market and I don't monitor Europe's market as well.
Edit:
Just checked out your opal-RT links and yes that is real time power systems software, just not the kinds of real time analysis I typically use and think of. This seems closer to PMUs (phasor measurement units) which instead of 4-second SCADA data use something to the tune of 60 samples a second (that's a lot of data).
I agree that Matlab and especially Mathematica is REALLY nice if they have a built in function for what you need (and they do have a ton of things as primitives like graphics, audio, a single import function that can read over 100 file types...it's nuts). If they don't have what you want, Wolfram Language is powerful but so weird.
What kind of case studies? The number one thing I care about in a scientific computing platform is library support: how does Julia perform on that?
Do they have ML libraries to compete with PyTorch and Tensorflow? How about geometric calculations such as Voronoi and Convex Hull? Can it handle noneuclidean geometry? Is there a good library for network analysis? GIS? Do they have a symbolic computation library to stand up to SymPy?
If Julia can answer Yes to all of the above, then maybe it's worth checking out.
Yes, yes, yes, yes? Flux.jl and KNet.jl. LightGraphs.jl. Etc. You can find these packages on JuliaObserver.com. Some of them are handled by PyCall interfaces: SymPy.jl, SymEngine.jl, QHull.jl, etc.
Sweet, PyCall looks awesome and exactly what I was hoping for. Full interop with no copying; I look forward to learning how it was implemented. Thanks!
Is there a mature option for calling Julia from Python?
Like RCall.jl and PyCall.jl? These have been around for awhile and are pretty simple to use. Just `@pyimport Package` and now `Package.function()` works, along with other things.
John Harrop himself posted on reddit awhile back that he hadn't personally used OCaml in a long time when someone asked about the book on the OCaml sub reddit. His username starts with jdh I think. Honestly though, scientific computing seems to be going Julia
He’s mainly converted to F# if I remember correctly. He was often in flamewars on OCaml mailing lists about multicore support.
There is a bit of hype around Julia but it’s use in the real world is a rounding error compared to Python, R, MATLAB, FORTRAN etc etc. I might look at it again in 5 years or so. OCaml never gained any significant traction in scientific or numerical computing.
Not OP but it explains why Ocalm is really good for the sort of code numerical science would turn to C++ or Fortran more stereotypically. I.e instead of focusing on programming for programming's sake (as introductory programming books sometimes tend to do) it actually digs into real applications, specifically, where a non-trivial problem is solved with elegant, short, readable and correct code.
If memory serves (I don't have my copy to hand) it focuses particularly on analysis and visualisation, and a lot of the examples are scientific in nature.
It was a surprising language decision to find out that OCaml didn't do implement polymorphic behaviour for common operations and opted to stress static types for things like print_int or 1.0 +. 1.0...
One reason is that promotion from int to float is not free! Therefore maybe it should be explicit that your code is doing that especially in a language like OCaml that cares a lot about performance and is used in a few performance-sensitive areas (notably HFT).
You can have overloaded functions without having type promotions. `1 + 2` would call `addInt`, `1.0 + 2.0` would call `addDouble` and `1 + 2.0` would be a type error, requiring manual conversion in order to fix it.
Nor is it safe to allow implicit conversion in general, but F# shows that you don’t need separate operators for floating point. You just need a compiler that refuses to implicitly convert data types, as F# does, so you must use explicit conversions and type suffixes if you want to mix data types. If you manually convert, then on your head be the consequences.
This is not legal F#:
let x = 1.0 + 1
But both of these are legal:
let x = 1.0 + 1.0
let y = 1.0 + float 1
F# doesn’t even let you mix single- and double-precision FP:
let x = 1.0f + 1.0 // ILLEGAL
let x = 1.0f + float32 1 // legal
And both F# and sml have a problem with that. What type should this function have:
let add x y = x + y
The proper solution for ad-hoc polymorphism is either dynamic dispatching (aka oop solution) or type-classes or OCaml's modular implicits, not ad-hoc monkey patches like that. And I find (+.) fine since float addition is not an arithmetic addition.
If you don't call it, F# simply guesses "int -> int -> int". If you pass a float, you get back a curried function taking float and returning float. Now that the "add" function's type is known, you now can't pass an int: that's now known to be an error.
It doesn't have any way to add ints to floats directly. You have to convert one to the other then perform the addition.
Haskell or Rust are the same incidentally: while the same "lexical" operator is used all the time (`+`), numeric additions are defined for two values of the exact same concrete type e.g. in Haskell you can add two Int or to Float or two Integer, but not an Int and an Integer, or an Int and a Float:
Prelude> (1::Int) + (1::Int)
2
Prelude> (1::Integer) + (1::Integer)
2
Prelude> (1::Float) + (1::Float)
2.0
<interactive>:6:15: error:
• Couldn't match expected type ‘Float’ with actual type ‘Int’
• In the second argument of ‘(+)’, namely ‘(1 :: Int)’
In the expression: (1 :: Float) + (1 :: Int)
In an equation for ‘it’: it = (1 :: Float) + (1 :: Int)
While true, that issue arose because you restricted their types. Without the type annotations it would have worked just fine, because the (+) function is polymorphic in the Num typeclass, and because literals are overloaded such that the literal 1 will have type Fractional a when type inference calls for it.
So in ghci:
Prelude> let x = 1 + 1.0
Prelude> :t x
x :: Fractional a => a
Prelude> x
2.0
> While true, that issue arose because you restricted their types.
What I was intending to show occurred because I engineered the example to show it, yes, that was the entire point.
> Without the type annotations it would have worked just fine
Without the type annotation it would have been in an actual codebase rather than the REPL, and that codebase would have been typed.
> because the (+) function is polymorphic in the Num typeclass, and because literals are overloaded such that the literal 1 will have type Fractional a when type inference calls for it.
Which does not contradict my point at all.
> So in ghci:
Which works because (drumroll) both operands are of the same Fractional type. Which is the entire point of my comment: Haskell does not allow adding numbers of different types with one another any more than OCaml does.
I initially hated the separate operators for floats and integers.
I've since grown to like it, because the only times I've been caught out by it is when I've made a mistake or I've forgotten I was working with floats.
Don't let the syntax put you off Ocaml, because there is some reasoning behind it. It's a multi-paradigm language that has a lot of powerful features.
Reason calls itself Javascript 2030. That's not a completely unreasonable time line for ML languages to go from the small percentage that they have now to being in the top say 5-10 languages used.
React has made the probability much higher. Reason is kinda like JS the good parts + Immutable JS + Typescript + Redux. Plus it works well with React. If your team is using React there's a good chance you'd get a benefit from implementing Reason in a few places with little risk.
I don't see why these two are being lumped together. I see ReasonML needs OCaml, but not that OCaml needs ReasonML. OCaml I expect will become increasingly mainstream - I've started using it instead of rust on personal projects. ReasonML would increase exposure to OCaml, but OCaml in no way needs it to succeed.
ReasonML was written in SML then they switched to Ocaml because everyone at Facebook already knew it and caml4p is a thing.
Because it is "just Ocaml", all the weird parts of Ocaml bleed through the reason language design. No operator overloading, nominal record typing, 3 competing standard libraries (plus the all-too-small actual standard library). The list of oddities is rather long.
SML was and is a better choice. SML has structurally typed objects and first-class constructors. No named arguments, but structurally typed objects do a better job at this (like JS destructuring, but more efficient). Anonymous records are possible. A ref type rather than mutable record fields. Only one `let`. PolyML has shipped a multi-process implementation for years while Ocaml's is still in an unending beta. SuccessorML (SML 2.0) is adding some syntactic niceties along with things like module typeclasses (modules should prevent the typeclass hell of Haskell). Most importantly, SML is a standard with multiple implementations and isn't completely tied to the success of Jane Street.
It doesn't seem odd to me to lump them together. Reason is just an alternate syntax for Ocaml, and because of this the "Reason toolchain" is usable with Ocaml code as well, and with mixed Reason/Ocaml projects.
I think it hits a sweet spot. Not as boring as Go, not as obstinate and distracting as Rust ("I'm sorry, Dave"), not purely functional for those who don't want to go all the way in that direction. I expect people who try those languages and decide "not quite" might try OCaml and find it more flexible and elegant. It's appearing more often in the "who's hiring" posts. There are the characteristics such as compilation speed vs others which could do with being, ahem, compiled into a post somewhere, if not already.
> not purely functional for those who don't want to go all the way in that direction
That's why I first loved it. I liked what I knew of Haskell but was skeptical of the Monadic IO system (I've since warmed to the idea). OCaml was in a perfect sweet spot in my opinion.
Also it feels a bit less abstract in some difficult to define way - I don't think Monads really clicked for me until I was using Options in OCaml.
I'll also second the opinion that as a _language_ OCaml is more ergonomic than Rust. However, I find that Rust is more _community ergonomic_ - it's easier to find libraries and contribute to them. Related to that - the build process is just spot-on. With OCaml, I found myself tripping over obscure errors in my build process about every month or so.
For me, OCaml is a bit like the one that got away.
But I'm excited about the momentum behind the Reason project!
To my knowledge, Reason is just an alternate syntax over OCaml and the two can be converted to each other. Thus, Reason should have the same semantics as OCaml. As OCaml isn’t just targeted at JavaScript, IMO adding async/await sugar for Reason wouldn’t make sense. (I assume that you mean syntax that desugars to JS promises. Correct me if I misunderstood.)
Although, it would be pretty cool if OCaml got some kind of do-notation (like Haskell), a generalization of async/await sugar for any monad structure...
It depends on very random factors and events, like with (almost) any other programming language.
How could anybody rate a probability of some experimental language from Sun research lab - the tiny, fast, garbage-collected, object-oriented language for embedded systems to become mainstream - before the language was renamed from Oak to Java?
What's the current state of F# on non-MS platforms? How does it compare to OCaml or F# on Windows? I've always wanted to get into it but for some reason (jvm ecosystem?) thought a cross-platform, multilang env would have advantages.
It's very good right now, especially with .NET core the new dotnet command, and VSCode's great support it's easier than ever to develop in F# on any platform.
Note: there's a very big difference between "native compilation" and the product known as ".NET Native".
.NET Native is a proprietary, Windows-only backend compiler toolchain for statically linking and tree-shaking compiled IL, used only for UWP apps on Windows 10 devices. It is this toolchain that does not support F#.
Beyond that, there are no toolchains for compiling to a single, native binary that are a shipping part of the .NET product.
We are not prioritizing .NET Native for F# at this time (from the F# team perspective), as we feel that .NET Core gives us more reach for F#.
As someone who's interested in F#, but has zero interest in ".NET", I hope for F# to someday become available as an independent language with native compilation and minimal runtime -- no Mono, no CLR, native platform support on Linux and Mac, and so on. But it sounds like that's not the direction things are going in?
Although there are counter-examples of this (F# on the web via Fable[0] is one), F# is fundamentally a .NET language. There were many decisions in its design that are a direct result of running on .NET:
* Object programming with F# is based on .NET objects
* Generics in F# are based on .NET generics
* Reflection-based features are based on .NET reflection
* Structs in F# are based on .NET value types
* Newer features in F# 4.5 are based on newer .NET features
* Forthcoming nullability features will be based on nullability annotations in .NET metadata
It's impossible to divorce the two, even if the target runtime environment is not necessary a .NET runtime. Those other environments inherent language design decisions made with .NET as a target runtime. The .NET runtime with .NET Core is indeed minimal, is natively supported just about everywhere, and was built with cross-platform in mind. F# is a part of this, for better or worse.
It would surely be a lot of work, but “impossible?”
I think you’re missing a couple of major tricks by not doing a native code compiler for F#:
1. Now that Moore’s Law^H^H^HBusiness Rule has run dry, we can’t continue to just pile up the abstraction layers. Some sage once said that every problem in CS can be solved by adding another layer of abstraction, but there’s one that can’t: make it faster without buying more hardware. Given how popular FP is among the quants, a field often going after microsecond latencies, I’d think this would be a constant refrain from potential customers.
2. I don’t want to ship a dotnet runtime to my customers. Just this morning, I had to update a customer accessible only via a highly restrictive VPN, where they haven’t given my server DNS access, much less unfiiltered Internet access. Everything I ship to them has to be scp’d to the server over the VPN. I really really don’t want to send each such customer hundreds of megs of dotnet runtime stuff, then be forced to work around the failure of “dotnet restore”, so I’m going right back to C++ so I can get native binaries.
Hundreds of megs might be charitable. I just did a “du” of /usr/local/share/dotnet on a workstation here and got 1.4 GB. Presumably that compresses down to mere hundreds of megs. Contrast the size of a “Hello world” binary, which I’d expect to be under 10 kB.
I want to like F# on dotnet, but you’re making it hard for me to use it in practice.
I'm not sure what your environment looks like, but the .NET runtime is not even close to hundreds of MB in size. Unless you distributed a large amount of resources in your self-contained distribution (e.g., many massive images) would it come close to approaching that size.
A development environment includes the .NET SDK, shared framework, and NuGet packages. So that's going to be large in size. But you should never distribute the SDK with a published application. That's pushing a development environment onto a production machine.
Yes, you're right, I shouldn't use the development tree for my comparison here. The runtime-only .NET Core 2.1.3 installer for my platform is only (cough) 26.3 MB.
If you then try to get that lower by using self-contained builds, you can only get "Hello, world!" down to about 20 MB:
$ dotnet new console --language f# -n hello
$ cd hello
...add <RuntimeIdentifier>osx.10.13-x64</RuntimeIdentifier> to fsproj
$ dotnet publish --self-contained -c release
$ cd bin/release/netcoreapp2.1/osx.10.13-x64/publish
$ rm -r ?? ??-?? zh-* # nuke i18n
$ tar -cvJf ~/Desktop/hello.tar.xz .
You'll notice that I'm giving you the benefit of high compression here. The unpacked tree is 70 MB!
The equivalent in C++ is 3.3 kB.
I'm not expecting miracles. As I said, I'd be happy with "only" a 3x ballooning here, roughly commensurate with the coding efficiency benefit. That's fair.
Just to clarify my other point, it is strictly impossible to undo the .NET-influenced language design decisions of F# without either making massively breaking changes, or writing a brand-new language with F#-like syntax and F#-like semantics.
1. Cleaner syntax. F# shows that we can do away with a lot of the visual noise in OCaml. I’m no particular fan of white space scoping, but I also don’t mind it.
2. Much better thought out standard library. The OCaml standard library was clearly accreted over long periods, with no strong designer making hard choices about naming and such. The example that keeps coming back to me is “big_int” vs all the other integer data types.
I believe #2 is what the OP meant by “minimal runtime.” A minimal F# will still need a good set of data types, a string library, etc.
Pretty much what wyoung2 said. F# feels much more modern than OCaml, with fewer weird warts. I don't know much about .NET, other than that I don't want it, just like I don't want the JVM.
I run F# on Mac, Windows and Linux, and my iPad Pro!
Continous app [1] allows for C# and F# with an IDE, interactive programming (continuous update as you modify code appearing like Lisp live development), debugging, code completion, object inspection, and it compiles on the iPad (or iPhone), no internet needed.
It pushed me to stick to learning F# now given how seamless the experience is on the iPad Pro.
No, Reason's actual name is Reason. The Reason ML name is similar to Go's "golang" name -- to work around the SEO nightmare the choice of the name really is. Your comment is otherwise correct in that Reason is an alternative syntax for good 'ole OCaml.
IIRC it was simply called Reason at first but then the slightly more descriptive ML was added for better searchability. People call it both Reason and Reason ML now. That seems fine to me :)
You are right it mostly is just a different syntax for OCaml but like in the Erlang/Elixir case there is a bit more to the story (js interop, js ecosystem, new ideas here and there, more diverse community as a result, etc).
I still call it reason, especially when I talk about it with other js developers ;)
This, F# is the modern and more friendly (syntax, interoperability ...) version of OCaml.
I'd say the link between TypeScript and F# is the pragmatic approach that Microsoft took. Different paradigms but with the same care for usability. They are both great language for projects.
Besides ReasonML (a dialect of Ocaml), if you’re looking for a layer on top of JavaScript or a supersets of JS that has a type system similar to or inspired by Ocaml, Flow comes closest: https://flow.org
Flow has a quite powerful type system that mimicks (and is inspired by) OCaml. Flow itself is written in Ocaml, by Facebook.
I disagree, Typescript has algebraic data types, conditional types, type inference, type guards, many or all of which are missing in Java. The class syntax is just another optional feature and it is possible to write quite functional / ocaml like code in typescript.
No and that’s one of biggest problems, pattern match is runtime decision not compile time one. It’s a shame because pattern matching with algebraic types is the full picture of the whole thing. Without it it’s just one-legged weirdo. It would be possible to emit runtime checks, similar to how tcomb+flow does it, but that’s not gonna happen anytime soon.
The goal of typescript is to provide static type analysis at compile time and mimic Ecmascript spec features. If Typescript starts bundling a runtime with it to do things completely unrelated to Javascript, then it's not just javascript with types anymore, it becomes its own language which defeats the entire purpose of Typescript.
This trade off is good because there is no runtime overhead, only desugaring. Typescript should never become ML or anything else that Javascript is not. If you want pattern matching in Typescript you need to convince the Ecma committee to put pattern matching into Javascript first.
When a language has algebraic data types -- i.e., data types that have multiple, disjoint constructors -- pattern matching generally means determining which constructor was used to create the value being matched, and branching on that. I'm guessing this is the kind of pattern-match that TypeScript users would be eager to have.
What I don't see is how this requires the addition of a "runtime" on top of the JS model to make it work. I don't use TypeScript, and don't know how it implements its data types, so there may be something obvious here that I'm missing.
Hi, lifelong python developer here. Is OCaml a good fit to do REST application servers? I've took a look a year ago but couldn't find well maintained libraries and it seems that the community is not so focused in general development. Am I wrong? OCaml seems really nice, I've been dabbling with rust for a while, and it feels great working with it but I'd like to try some purer functional languages too. My needs are basically a web container, some way to interface with SQL (ORM or a query builder, with support to PostGIS), some redis, some elasticsearch, nothing too fancy.
A great (albeit maybe not as great as OCaml ;) alternative for web usage would be F# with .NET Core, which has become a joy to work with over the past year or so on macos.
There are some features in OCaml that are interesting if you're coming from a Haskell background. In particular, polymorphic variants don't have an obvious analog in Haskell and can be used very expressively. Certain problems can be reasoned about more easily (at least for me) with strict evaluation, so some problems are easier to deal with/debug in OCaml.
it's a fairly different language. Haskell is lazy by default, Ocaml isn't. The Haskell type system makes use of side-effects explicit, and Ocaml does not. They're only similar in the sense that they're both functional languages.
Ocaml's module system is definitely worth looking at especially in contrast to Haskell's typeclass approach if you want to compare both languages.
It might be quite useful to look at BER MetaOCaml[1] at least. And maybe at some other ways to deal with some problems - like OCaml DSL instead of Haskell monad[2].
I'm not sure why this is linked. This online toplevel is very old.
People who want a more modern version, with more exercises should follow the online MOOC [1] or use this website [2].
People who just want an online OCaml/Reason interpreter to play with should use https://sketch.sh/ml
Because this is all on a single page and is a nice introduction to language people might not have coded in before (like me). That MOOC has a login wall and the other interpreter has no instructions, so I'm glad OP posted.
Well I did only discover this one today. I found it to be a nice little introduction, just enough to be interesting for others as well, hence the submission.
Also, you and others submitted so many more great links in this discussion, so I think all of this might be useful for others.
Programs written in ML dialects tend to have the astounding property that once they compile, they are correct. And this is only a slight exaggeration.
This property alone is worthwhile to learn one, if for nothing else then to be able to apply the same succesfull patterns in other languages.
I didn't know how to write proper strongly typed code until I learnt Ocaml - I had several years of experience in C++ and knew Java, but, they really don't go out of their way to expose the patterns that allow write the best code possible. With the lens of Ocaml under my belt I could better discern the shiny patterns that were buried all that ugly dirt of multiple inheritance and such bollocks.
Which ML language should you learn? Any of them is good as the next if it's for education - a modern tooling, support and community is a nice bonus.
ML languages in production nowadays include Ocaml, F# and, to some extent given it has so much isomorphism with its kin, Scala. Scala can be considered an ML dialect, although with the weirdest syntax of them all.
Unless you are quite certain Ocaml is the exact language you want to learn, F# is a good alternative.
I'd say Elm is a plausible alternative, though maybe not right now: there are a lot of small rough edges in the ecosystem after 0.19 release. On the other hand, a lot of the 0.x breakage comes from the very high priority of the unusual long-term plan, which I'd formulate as something like following: distill that essential property of ML while shaving all the bells and whistles that just happen to be in other dialects.
Long term: yes, the controversial banning of "native" code [1] is in part motivated by the idea that JS should be an interchangeable implementation detail.
Short term, officially: hell no, Evan declares a sharp focus on one use-case and discourages experiments with other platforms, even server-side node.js [2].
Short term, unofficially: I heard of a compiler to Elixir [3]. Elm's stance on "native code" (see above) seems to make such projects feasible.
Ocaml has an amazing type systems that’s been designed well from the ground up. There’s excellent pattern matching, no null/nil, immutability of values, higher-order functions, etc. The type systems of a lot of new languages have gotten their inspiration from OCaml. For example, the Flow type checker for JavaScript is heavily Ocaml-inspired and itself written in Ocaml.
Could you please tell us how rust is better at functional programming than OCaml?
Your comment appears unsubstantiated to me. I am not sure how you reached the conclusion of equating learning OCaml with learning BASIC, but I would be happy to know your reasoning.
It looks horrible to me. I use a lot of FP math, and I'm not going to pick up the habit of sprinkling these dots everywhere. The fact that the language designers would even seriously consider this solution tells me it's not for me.
What do you think?