Hacker News new | comments | show | ask | jobs | submit login
Reason ML toolchain (khoanguyen.me)
238 points by thangngoc89 10 months ago | hide | past | web | favorite | 100 comments



I've been following ReasonML pretty closely because, to me, it looks like the most promising compile-to-js language (functional, static types, but practical), and moreover, it can really bring a whole new set of people to the OCaml ecosystem, improving the tooling there. Idealistically, Reason is the language that lets you target any platform by either compiling to JS or native code.

That said, I recently tried rewriting some code, specifically a canvas-based game, in Reason, and while the language itself was amazing, the interop with the mutable JS canvas API was really annoying. To be honest though, not sure if games is what Reason is meant for so it's not a big deal. It's a great fit for React, which really leans heavily on the functional paradigms that Reason promotes.

Also given that FB has rewritten 50% of messenger in Reason, I don't see it dying any time soon. So here's hoping that it keeps growing and the tooling improves. I'd definitely like to see it become more beginner friendly, and additionally, I'd like to better understand how to interop with existing OCaml libraries and target the native platforms.


You may want to check out Fable[0] for F# if you haven't already. Syntax will be very familiar, and the interop[1] with JS is really great. There is also a tool to create bindings from Typescript declaration files[2].

[0] http://fable.io/

[1] http://fable.io/docs/interacting.html

[2] https://www.npmjs.com/package/ts2fable


Generally when it comes to interoperability with JS the problem stems from assumptions made by the people designing the JS APIs and what is idiomatic in the compiles-to-js Lang. Clojurescript, Reason, Purescript, and Elm all have a specific way they want to work and the browser APIs go against that.

If anyone has any advice on how to help this I am all ears but writing garbage interop code gets old.


I came to this conclusion over the weekend. Really wanted to use one of those compile to JS languages, but after doing some interop and looking at their output, you're fighting the browser. Even Clojurescript, which is supposed to have has great code elimination will produce much bigger outputs then regular JS.

One way to look at it is immutable.js minified is 55 KB. That's about 5,000 lines of JS. If you're using a functional language, you've gotta bring along those immutable datastructures somehow, and 5k lines of Clojure is gonna output greater than 5k lines of JS.


Keep a watch for the new Reason standard library, it will bring some stunning reductions in output code size. I mean, right now the output code size is about as minimal as you can get while looking like hand-written JS ... but what's coming might blow all the other immutable libs out of the water thanks to optimisations it can do using static typing information.


don't forget Clojurescript employs Google Closure compiler that has the best in the market dead-code elimination. Code on prod can be pretty small.


I found the interopt a bit cumbersome too, but I guess this is what you have to pay for a 100% typed codebase :/

I saw some people wrote games with Reprocessing, maybe this helps.

https://github.com/Schmavery/reprocessing


Hey author here,

Here is a successful story [1] of using reprocessing for making cross platform game (Android, iOS, macOS and Web) from Jared Forsyth

  [1] https://jaredforsyth.com/posts/making-a-cross-platform-mobile-game-in-reason-ocaml/


The interop is a bit cumbersome, but fortunately someone only has to do it once, like writing TypeScript interface files for existing libraries.


Reprocessing looks amazing, and I might give it a second try now. Thanks!


Interop was a little pain for me as well when testing ELM, so for practical reasons I'm ended using Typescript and I like it quite well but I think immutability by deafult is good step forward towards better programs and I'm happy FB engineers work on ReasonML.


One place you can see this in action is that [ ] are lists and [| |] are arrays.

JS favors arrays, OCaml lists, so you either write dsls with [| |] (ugly), or you import a module and convert from lists to arrays and your bundle size goes up 80 KB (don't recall if minified or not).

I was surprised to see Reason continue with this syntax. The idiomatic approach for either side is suboptimal unless I'm missing something.


What DSLs are you referring to here?

One reason to favor lists over arrays has been that they are immutable. Most of my personal JS array usages have been as dynamically sized arrays, because I’ll use .push all over the place. That usecase is the primary reason to use lists instead: it’s much faster to prepend and destructure on lists.


Something like Elm's Html module:

    div [ id "test" ] [ text "stuff" ]
vs

    div [| id "test" |] [| text "stuff" |]
If the JS library expects an array (not uncommon), that gets ugly quickly.


Hi, I'm pretty sure a tree-shaking bundler like Rollup can wipe out most of that bundle size by using only the list functions you need. Then again, if you need to use arrays, use arrays, [|1, 2, 3|] is not actually that bad–you get used to it pretty quickly.


I’d love to hear about better interop APIs. I think if there’s any way to make Bucklescript bindings easier, that would be tremendous.

In my experience, the crux of the difficulty actually comes from the JS APIs themselves working in a very JS-way, to be nice. Lots of DOM APIs rely on the dynamically typed nature of JS, making it super hard (probably impossible) to make statically typed bindings to.


The main advantage of building on the OCaml language is that it is possible to totally encapsulate an FFI binding in a way that doesn’t virally infect the code path that calls into it. In pure languages this may not be the case. OCaml is not a pure language and so neither is Reason.


If you're interested in ReasonML, you may also be interested in Elm http://elm-lang.org/.

Coming from JavaScript / React / Redux / Flow, ReasonML initially looked more familiar, but I still found Elm easier to pick up. Elm has a more unified feel. ReasonML read to me as an assemblage of components — each of them high quality, and expertly integrated, but it still felt like more different pieces all to learn at once. YMMV.

OTOH, you can't (currently) use Elm to write a native mobile app.


Facebook and Bloomberg, two large gorillas throwing their weight behind ReasonML+Bucklescript tooling. Elm is mostly Evan (with support of RedInk)working on the core/tooling with a lot of help from Richard Feldman on general ecosystem. No surprise here that ReasonML is gaining momentum fast.


One thing to remember is that Reason and BuckleScript are rather small projects, with not that many people employed to work on them. Their combined 'manpower' is not that much more than Elm's right now.

What they are cleverly leveraging is the twenty years of solid type theory (a sound type system), language design (more powerful pattern-matching, functions, syntax sugar), and engineering practice (the OPAM ecosystem) that has gone into OCaml.

This is why Reason/BuckleScript are able to punch above their weight class.


And if you are interested in Elm, but felt limited by the language, you may also be interested in PureScript or Haskell.

http://purescript-pux.org/

https://haskell-miso.org/

http://docs.reflex-frp.org/en/latest/


Initially for me Elm felt like a toy language that serious folks should ignore in favor of PureScript and similar. But then after reading code for various Elm applications I realized that I can grasp how things work just by reading the description of the state. Code was just filling details that can be ignored on the first reading. This does not happen with other functional languages when the code ended up passing various important bits of the state in lambdas of callbacks making understanding of the whole much harder.


I have the same concern, what is the performance of these frameworks in comparison to Elm? Elm is super fast compared to React and Angular [1], but what about these frameworks?

1. https://www.codementor.io/rudolfolah/elm-vs-react-developmen...


Framework performance should rarely be an issue in normal use, by super fast you're talking about milliseconds of difference to toggle hundreds of todo item.


It's worth being aware that the Haskell approach (and quite a few of these functional langs) add a lot of size to your bundle.

Hello world in that Haskell library was 1 MB last time it was posted.


If you’re building anything that shows a list of editable things in React, then you’re going to need shouldComponentUpdate() to avoid updating every list item view, every time you type a letter.

It’s virtually impossivle to get shouldComponentUpdate() right when you have ideomatic react with callback props, since callbacks can’t be reliably compared for equality.


Conversely, if you are interesting in both Elm and ReasonML there is Bucklescript-Tea - https://github.com/OvermindDL1/bucklescript-tea/.

The Elm architecture ported to Bucklescript.


there's also ocaml-vdom[0] which i've been enjoying using for a side project - it's built on top of lexifi's gen_js_api[1] and while a little bare-bones right now, is pretty easy to extend with the bindings you need.

[0] https://github.com/LexiFi/ocaml-vdom

[1] https://github.com/LexiFi/gen_js_api


Is it as fast as Elm?


I haven't tested the performance, but I see no reason why it shouldn't be.


The best thing about Elm to me is how it's innovated on tooling, and has trailblazed on the super readable error messages.

At the end of the day though, I don't understand the appeal. The people who really are into functional programming will gravitate towards GHCJS and PureScript whereas the ones that aren't as into it will be drawn to TypeScript and plain JS. I really don't get where Elm fits into it all.

I can see Reason being way more mainstream.


I'm really into functional programming and I gravitate toward Elm and away from PureScript and Haskell.

Fundamentally what appeals to me about Elm is the design sensibility of "what is the minimal set of primitives necessary to achieve a great user experience?"

Over the years Elm has gotten simpler and nicer at the same time. The last three major releases removed language features.

I love that! Building software is complex enough as it is; one of the things I like most about FP is that I no longer have to spend time thinking about objects, classes, inheritance, etc.

It frees up more of my brain to focus on building things!


I'm in the former category and am very enthusiastic about Elm. Reason is great and will probably be more popular overall as it's less of a leap for most JS devs as it utilizes patterns that are already being pushed as best practice and it's relatively loose in comparison. That being said, Elm offers a built-in architecture that reduces decision anxiety.


Reason also has the benefit of Bucklescript which has very high-quality JS output - very friendly to VMs, and the rest of the JS tooling ecosystem. This is something where Elm is sadly lagging quite behind.


Can you quantify this? In what sense is the JS output from Elm lagging behind? What is it about the JS output from Reason that makes it better?


Very bloated, lots of allocations, not compatible with other JS module systems, no uncurrying optimizations, no integer optimizations, etc. Bucklescript's output is pretty damn impressive on the other hand: https://reasonml.github.io/en/try.html (check out the factorial example, for instance)


I've never noticed runtime issues with Elm.


My biggest gripes with Elm are cumbersome JS interop, and the fact that the output for a hello world when gzipped and minified is still 43kb.


I get what you're saying - as someone who is very concerned about bundle sizes currently - but if you are using something like Elm door a help world, you are already losing. Elm is for complex, highly dynamic user interfaces that need a high level of durability and maintainability. Toy projects like the one you describe are useful for learning the language and it's patterns, but for practical purposes it's like bringing in a concrete truck to patch a hole in your driveway.

Also, that bundle size is still smaller than react + react Dom. And you get the features of redux and immutable for free plus a solid, statically checked type system.


Yeah, bundle size isn't a real deal breaker, but it does make it a bit harder to roll into an existing project in small chunks. My main issue is the interop portion.


I'd like to hear about your pain points with interop. I'll more than likely be talking to Evan soon and I can discuss with him. Also, he's pretty responsive in general. The community is pretty eager to help with these sorts of pain points - join the Slack.


I think my biggest issue was the lack of any escape hatch for the development process. When you're trying to interop with JS and have to reason through the types that should be associated with the return value it can be a real slog if the JS returns a deeply nested object. I like that BuckleScript/ReasonML allows you to experiment with raw JS while figuring out the types.


One thing to remember is that you only need to decode the fields that you need access to in elm. You don't have to reason about the whole data structure of it's not used in your program. But I feel you, in JavaScript you can just kind of wing it. But I think there a lot of value in the more deliberate approach. And for your work you are awarded with zero runtime exceptions - which is a pretty amazing guarantee which I've seen be largely born out in practice


As I understand it, the upcoming Elm 0.19 compiler will do dead code elimination for the output bundle.


Ah, that's great to hear!


I was looking into ReasonML a few weeks back because the promise of whatr it offered was so great. Write in one language, and run on the server and on the client, but allow the server to be compiled natively for speed. This really appealed to me, especially because there are some times that I really wish I had some utilities I had written on the back-end available on the front end.

Unfortunately, what you appear to have currently is that a lot of the tools and utilities you would want to use in ReasonML are written in either JS of Ocaml, and reply on the interop when you target that platform. Want an ORM? There's a couple, but they are all targeted at Ocaml, so you either compile to native and link or try to port the Ocaml source of it to ReasonML (maybe automatically?) and maintain it. Want a web router/framework? There's a lot written in JS, but you'll be configuring and writing some JS most likely to get it to work, and no compiling that natively. This is a recurring theme. Most robust larger packages are in one language or another, which causes problems for anyone wanting to leverage the inherent advantages of both target formats.

What it seems to come down to is that Reason needs a whole lot more software written in Reason so it's more flexible. Being able to use Ocaml and JS packages is a feature and liberating, nut having to use Ocaml or JS packages ends up putting constraints on your project. ReasonML has a lot of promise, but at least for what I was excited about, it can't deliver. Yet.


I understand what you're saying. Many native OCaml libs are not portable to JS, and you definitely can't port a JS lib to OCaml with the current toolset, which prevents the dream of being able to not care at all about runtime. It's the same dream I've been chasing on the Clojure(Script) side lately as well.

I believe you can get close in ReasonML by making a clear distinction between client (JS) and server (native), and then maintaining a common module of business logic and utilities that you would want to share between the two. This works well up to the point where you want to server-render some HTML, at which point you become sad because you'd love to use the nice ReasonReact component abstraction, but it is not at all portable to native.

Jared Forsythe has been doing a lot of work on making portable applications and libraries in ReasonML, and I do believe that the native compilation story will receive enough love that more people start taking it more seriously - right now the majority of time + energy of the ReasonML team seems to be focusing on honing JS application development, so most of the community is orbiting that use case.


> I believe you can get close in ReasonML by making a clear distinction between client (JS) and server (native), and then maintaining a common module of business logic and utilities that you would want to share between the two.

That was the conclusion I came to as well, but I decided it wasn't worth doing so at this stage. I think eventually the ReasonML ecosystem will grow enough to make this much easier. It's nice that you can use Ocaml libs and Js libs in instances, but I think there are use cases where people mistake can for sufficient, when in those cases it's not.

Ideally this would be solved by pushing Ocaml libs towards JS, but I'm not sure how much attention Ocaml has gotten with respect to we stacks (even the lower end of web stacks). It's unclear to me whether high quality libs exist to push towards JS to all the needs that exist in that space.


Hey author here,

I think I failed to explain about this in the article. OCaml and ReasonML is the SAME language with different syntax. You don't need to worry whether the library is written in OCaml or ReasonML as long as your build tool support both ReasonML and OCaml.


I'm not sure you understood what my point was. I was looking at reason as a replacement solution for my current stack, and the entire stack. That includes optimized multiprocessing code, processing daemons, ORM DB access (mostly a good query builder and normalized operations), a web framework, and HTML/JS page rendering/serving (I don't really care if it's rendered at the client or server level).

Right now it's 90%+ Perl, which I'm for the most part happy with, and the rest is JS, which I'm not exactly thrilled to deal with (Perl and JS are similar enough in some respects to make the parts of JS they flubbed really annoying). The main draw of ReasonML for me was the ability to have a stack of a single language that reached all the way up to the client browser and all the way down to the multi-process data retrieval and processing system.

What the current status quo looks like, from an outsider, is that ReasonML is used well by people familiar with the Ocaml ecosystem to supplement and write Ocaml through a different syntax. It's also used by people familiar with Javascript to write Javascript to supplement and write Javascript through a different syntax. It works well in each of these domains, and is able to use the ecosystem of tools in each domains, but where they meet gets a little fuzzy, the packages are sparse for both domains, and there's less people already working in that space (and I'm not interested in solving problems because I'm the first in this instance).

This sort of comes to a head around the webserver and/or framework. There are choices in both Javascript and Ocaml. Some of the Ocaml suggestions seemed like a good bet because I could compile the server side to mostly binaries, but how well tested are they? How well built out with features? The ones I saw seemed a bit more bare bones than I was hoping, which might be expected from an ecosystem that has been mostly compiled and focused on application and systems code. So, do I choose Node and some Javascript routing framework and helper libraries? How does that complicate any code sharing I want to do, if there's different HTTP subsystems depending on whether I'm using a JS back-end or Ocaml libraries?

I also looked at doing more JS for the back-end, and just using Node to run everything. Unfortunately, Javascript libraries targeted at the system leave a lot to be desired in my opinion, and I wasn't finding much in the way of a good ORM or query builder that I thought sufficient, and a good database abstraction layer. Again, I'm finding this middle-ground to be weakly supported.

I'm seeing now from replies that there are Ocaml to JS transpilers that would possibly solve some of these problems for me by pushing more of the Ocaml stack to Javascript, but I'm also not sure how I feel about committing to what might be a fragile or error prone process, or how well that interacts with other parts of the system.

In summary, it really felt like there are two strong sub-communities in ReasonML, the Ocaml systems people and the Javascript/React/Web people. They both have a growing ecosystem of packages around them, but they don't necessarily play as well with each other as they could, and getting to that point will allow ReasonML to fulfill a lot of its promise.

Edit: As an aside, from a sysadmin perspective, it's somewhat troubling that the bucklescript toolchain fails to install through NPM as root. Leaving aside whether it's a good idea to have it installed as root (or for that matter whether NPM should ever be run as root), it bothers me that it would fail in some unknown way on a recent RHEL/CentOS system. Failing specifically because it doesn't want to be installed as root with a notice saying as much would have been acceptable, but having a bug like that exist makes me feel like there's not enough people using the system yet to shake out the bugs. It did damage my confidence in the toolchain somewhat.


Any Reason code can be linked to OCaml code, because OCaml = Reason. In fact, they are only syntactically different. That is, Reason is an alternate syntax for OCaml. BuckleScript/js_of_ocaml can be used in either language, which is to say that any OCaml code can be compiled to JS libraries assuming there are no dependencies that will fail on JS (no need to convert to Reason code or anything).

> Being able to use Ocaml [...] packages is a feature

It's not, it's a necessity. OCaml and Reason are the same language; it's not like Erlang vs. Elixir which both run on BEAM.


But that's just syntax. As you say, it doesn't mean an arbitrary library written in OCaml will actually run in the browser due to dependencies. It doesn't matter if you can link the code if it won't actually work.

I'm reminded of GWT where there is client-only Java, server-only Java, and portable (shared) Java. It's all Java but you definitely have to keep your desired platform's constraints in mind when looking for a library to reuse.


You can try Doppio and JavaPoly. Its a full JVM running on JS, and works with most Java libraries that don't do things which would go against what the JS sandbox is allowed to do.


Last time I used Doppio, it was really slow. As in something that took 10s on the jvm took hours on Doppio; has performance improved in the last couple of years?


Are you saying pure Reason,possibly with some JS interop isn't possible? Because that sounds like not using an Ocaml packages to me, which means they aren't a necessity.


He's saying Reason = OCaml. OCaml can be compiled to to either a native executable, native bytecode, or JS.

His comment may sound like a bit of an non-sequitur, but really the confusion comes from: it's not a delineation between OCaml and Reason, but native packages vs. packages that are designed with JS interop in mind.

Some native packages can be compiled to JS (e.g. if they don't rely on C FFI), but many interesting ones cannot. js_of_ocaml's version of this story is much better than bucklescript's, but honestly I haven't explored it that much in either one.

So what you're saying - write pure OCaml/Reason code, with some JS interop, without relying on native OCaml/Reason packages - is certainly possible! And is probably the most common way of writing apps using the ReasonML syntax today.


Pure Reason exists, but you can just use `refmt` to convert any OCaml code to Reason (which isn't even necessary, since they both get compiled to the same thing and are stored in the same syntax tree).


What I was commenting on was the statement that being able to use Ocaml packages is a necessity, and specifically as a rebuttal to my saying being able to use them is a feature.

The implication I get from that is that pure ReasonML to JS without Ocaml packages is not possible, which is why I asked.

There of course may be some difference on what people consider an Ocaml package, but I would consider anything ReasonML comes with as available in the core as not an Ocaml package, even if that's what provides the support underneath it all, as it's now part of the ReasonML spec (and if the Ocaml package was deprecated, they would find some other way to provide the same underlying functionality so the API did not change).

In any case, that statement about it being a necessity confused me.


Sorry, to clarify I mean that by design OCaml = Reason. The only way it would not be possible to link the two would be with artificial restrictions. Though they are very different looking, they share the exact same semantics, type system, module system, compiler pipeline, etc. Past parsing, the two languages become the same. I used necessity to mean that for ReasonML to exist, it must be possible (rather than that all Reason programs must necessarily import native OCaml code).


js_of_ocaml[1] is an ocaml to JavaScript compiler that can actually handle the entire ocaml language (because it compiles ocaml bytecode to JavaScript). Sounds like it’s more what you’re looking for than Bucklescript (the ocaml to JavaScript compiler Reason uses by default.) Since Reason is just an alternate syntax for ocaml, you can use it with js_of_ocaml as well.

[1]: https://github.com/ocsigen/js_of_ocaml


Yes. js_of_ocaml has different goal with Bucklescript. I addressed this in article. Funny fact, Bucklescript could be compiled with js_of_ocaml for running on the web. More details: https://github.com/glennsl/bs-in-a-box


I've done cross-platform development with Scala (JVM/JS). I'll tell you, with all the tooling support (sbt) that Scala has right now, it's not all that much easier than what you can do with Reason.

Typically, you get libraries like `foo-scalajs` and `foo-scala` which are basically cross-compiled from a single codebase which is divided into three major parts: common, JS, and JVM.

With Reason you can do the same thing (in fact people have). On top of which, Reason's functors (higher-order modules) allow you to write for multiple platforms in a very clean and decoupled way. They are a great, great boon for software engineering and folks like e.g. the MirageOS have used them to great advantage to target say the unikernel and Unix environments for their apps.


ReasonML is IMO quite ready for production work if you use it for building server-side applications with NodeJS or rich front-end applications with React (ReasonReact).

The target audience for Reason (at least for the moment) are web application developers who want to level up as programmers and want to build elegant, sturdy production systems.

Reason and Elm together are democratizing statically typed functional programming and I believe that the next 10 years are going to see a massive change in the programming language landscape, with the practice of typed FP finally finding adoption in mainstream commercial programming.

The allure of Reason is in its packaging of OCaml to the web browser (which is made possible by BuckleScript - the actual OCaml to JS compiler doing the heavy lifting), its syntax that is familiar to the vast majority of programmers today, and the large ecosystem of bindings, libraries, and documentation that the team has put out.

OCaml is a very pragmatic language; its main pull is its powerful static type system and immutable, functional programming, but the "O" in OCaml stands for "Objective" - it is an implementation of CAML with support for object-oriented programming. But you almost never need objects. OCaml's module system and its idioms allows you to write well-encapsulated code without mutation, and when you actually need to write honest to metal imperative code, you can do it with abandon because OCaml is not a "pure" functional language like Haskell.

The term static type system might put off programmers whose only exposure to types were with Java, C++, C# and similar languages. But this thing is very different. Types in OCaml are more like structs in C; you just say the shape of your data, and you write pure functions that operate on them, and that's pretty much it. The magic happens in how you define the shape of your data. "Making invalid states impossible" is the siren call for statically typed FP languages, and from that flows a lot of natural constraints that can teach us how to structure programs.

The following links illustrate the promise of Typed FP very nicely, do watch it so that you'll have some inkling of the fun you'll have when you start learning ReasonML:

Designing with Types: Making illegal states unrepresentable by Scott Wlaschin. https://fsharpforfunandprofit.com/posts/designing-with-types...

"Making Impossible States Impossible" by Richard Feldman. https://www.youtube.com/watch?v=IcgmSRJHu_8

Ideology by Gary Bernhardt. https://www.destroyallsoftware.com/talks/ideology

Effective ML Revisited by Yaron Minsky. https://blog.janestreet.com/effective-ml-revisited/

Programming Languages, Part A by Dan Grossman. https://www.coursera.org/learn/programming-languages


> Write in one language, and run on the server and on the client, but allow the server to be compiled natively for speed

A lot of the JVM languages allow for this. Kotlin, Scala, Clojure and Fantom come to mind. They all can compile to JS also, allowing for code reuse between frontend and backend.


Well, sure, but ReasonML also natively supports JSX, has am included reason-react package and has Facebook behind it. To me that signals not just that it targets JS, but that it targets JS in a way and with tooling and abilities that convey advantages to using it for web development.

Some or all of the other languages you mentioned might as well, but if they do I'm unaware of it.


Thanks, this was helpful as someone who's interested in this set of tools but hasn't been following closely enough to understand how they all fit together (e.g. why there's both js_of_ocaml and Bucklescript, and how ReasonML fits into this).

For my own needs, it still seems unclear which way I should go though. The attractive thing about the tools to me is that you can write code that compiles to native and web, in a more or less MLish way (which I like). But it seems like either route works for that. I could just write OCaml, using the regular native toolchain for native compilation, and either Bucklescript or js_of_ocaml to compile to web. Or, I could use the ReasonML toolchain instead. If I'm not primarily a JS dev, is there a reason to pick one or the other? The syntax differences so far don't jump out at me as exciting enough to be decisive. I guess I could try a small side project in each and see how it goes.


I think why you'd pick Reason over OCaml boils down to whether you prefer the Reason syntax more, and perhaps that it'll have more mindshare than OCaml in the future. I think the question is similar to why you'd pick Elixir over Erlang.


One thing I’ll add on top of the other comments is that the Reason community has been trying hard to build tools and libraries for people who are building products. Doing that for two reasons: 1) Most of Reason contributors are actually working on a product, and contribute to Reason on the side (20% or personal time kinda thing) 2) Product driven dev allows us to build simpler things that solve real problems that people have :) This means that the Reason tools are less powerful but also simpler. In particular I’m thinking of bsb (https://bucklescript.github.io/docs/en/build-overview.html#d...) and bsb-native (https://github.com/bsansouci/bsb-native), the latter’s a simple fork of the former that adds support for building to native. Bsb is simple and thanks to that very fast and easy to setup.


Hey author here,

This boiled down to where you like C-like syntax or ML-like syntax. You could use refmt to convert between OCaml and Reason syntax automatically. Once you know the language, you can use both of them without any problems


If you want to potentially develop for native, make sure to install the OPAM toolchain, it will give you access to the existing OCaml native ecosystem.

Reason is also easy to install from OPAM https://reasonml.github.io/docs/en/global-installation.html#...

Remember that BuckleScript is a separate thing which you can get any time with just `npm install --global bs-platform`


It's not just about languages. Try out both communities and see which you might prefer to interact with in the medium/longer term. As you suggest, small side projects with each would be a good way to go.


Last time I tried Reason, it seemed like the OCaml toolchain was all but neglected. For whatever reason (no pun intended), it seems like it's assumed that Reason only targets JS in practice. It seems like the best way to target the server or desktop is by way of Node. :(


Reason targets JS programmers. OCaml's toolchain is great honestly, it just seems like ~85% of Reason users are more focused on the JS parts of the language, so what happens is the new users from Reason don't really do much to contribute to the native toolchain (though any libraries they write can mostly be used with the native toolchain, which is really nice!). The other thing is, most of the compiler programmers came to OCaml because it was an ML, and I think for the most part this group will continue to use the ML syntax and self-selects for the group that prefers it. So in reality, it's a little bit crazy to expect the Reason users to be the ones rapidly changing the toolchain. That said, this will continue to bring more attention to OCaml and hopefully more funding that can help solidify things like multicore, modular implicits, and everything else making its way through the compiler development pipeline at 2mph.


> So in reality, it's a little bit crazy to expect the Reason users to be the ones rapidly changing the toolchain.

That's too bad, because all of the marketing (at least around the time I initially looked into it) was something like "OCaml for humans". The JS bit was mentioned as a footnote, but then when I looked at it, JS was the primary target.

I was half hoping that Reason would fix some problems that keep me (and probably many others from OCaml):

* Fragmented build tooling ecosystem with no outstanding options (ideally the Reason community would build a standard tool that improves on other options)

* Fragmented standard library ecosystem with no outstanding options (ideally the Reason community would standardize on a std lib, but this might be overly optimistic)

* Syntax (obviously this is Reason's target problem, but not the most important issue)

* Parallelism (well, Reason probably would never address this one)


I think it stands to fix the fragmented ecosystem by shear force. The masses will decide what will become the de facto standard. For now, it seems like jbuilder will be the winner.


This is a small nitpick but the line: "OCaml's compiler is pretty unique, it's a set of pluggable parts that can be replaced and used together." is inaccurate. Most modern compilers are broken up into backends and frontends now, e.g. LLVM, JVM, .NET, etc.


Is the OCaml compiler really the same as those others though? I'd say it's more complex than that. It has a very large middle-end that most compilers don't. Things that are pluggable so far:

- Lexing/Parsing (ReasonML) - Preprocessing (PPX) - Backend (BuckleScript/js_of_ocaml)

Other parts of the compiler (not as pluggable?):

- Typechecking (which is really what makes it OCaml; TyPpx allows some changes) - Semantics (can be overridden with PPX somewhat) - Optimizations/middle passes (things like Flambda)


As an example of such architecture already in the 70's.

PL/8, used by IBM for doing their RISC research.

An Overview of the PL.8 Compiler (1982)

http://rsim.cs.illinois.edu/arch/qual_papers/compilers/ausla...


Hey author here,

I'll look into this and update the post accordingly. Thank you


No problem. Thanks for documenting the ReasonML toolchain and how it relates to OCaml.


Since a lot of people are coming to OCaml for the first time through ReasonML, maybe this gotcha might be helpful:

I was having a really hard time doing `npm install -g bs-platform`. I kept getting "linking" errors that I didn't understand, since I'm new to Ocaml. It turned out that I needed to get rid of my ~/.opam directory. I did `mv ~/.opam .opambk`, then `npm install -g bs-platform` suddenly worked!

Sweet! Looking forward to playing with ReasonML/OCaml!


Thanks for the tip. Also, we are working on making it easier to isolate opam packages and npm packages side by side in one development environment so that problems like this are avoided. This allows you to build a project that depends on opam packages for build time tooling inside your JS projects. That project is called esy, and it’s a young addition to the ecosystem but something I’ve been using to greatly increase my own productivity for a while now. It will not make BuckleScript compile opam packages (that is not BuckleScript’s goal) but it will at least make the two ecosystems coexist simultaneously.


That's so important. Tooling can make or break a platform for me. I've tried Haskell like 5 times and just never felt motivated enough to make it past the various little issues that kept popping up.

So far OCaml seems like a bit of a smoother experience.


Hopefully they'll get theit async story sorted out fast.

That's the only thing holding me back right now.


Could you elaborate on that? Do you mean async on frontend as in javascript async/await or do you mean async on the backend as in threads etc?


The first.

As far as I know OCaml and JS have stuff to handle this (lwt, promises, event-loop etc.) but the usage in the "front-end" isn't so nice ATM.


I looked at ReasonML couple weeks back intrigued by Jared's post (referenced in this thread as well) I noticed mentions about OCaml not supporting Unicode. I was wondering what does that actually mean? If you target native you have to find good external libraries for Unicode string manipulation? Or that text handling in OCaml (and thus Reason) is harder compared to facilities in, say, JavaScript and Python?

Other than that bit Reason React looks very promising. My usual use case tends to start with arbitrary JSON source I'd like to build a tool for. Due to strict typing this runs headlong into hurdles that have ended my explorations...


What that means is that the language itself has no built-in constructs to distinguish Unicode, or any other encoding by default.

OCaml's string type is more akin to an array of chars in C, in that it just represents a series of bytes. There's nothing about the string type that describes the contents of the bytes. So while you could put ascii in there, when you to print the contents, it's up to the terminal emulator to decide how to interpret those bytes.

One thing which you can do is include Unicode characters and save them in an OCaml source file. The string type will capture the byte representation just fine.

If you want to enrich the string type to also include format information, you might have to look for other libraries.

And, one last point about the string type: traditionally the string type allowed for mutation. In the last few years this behavior has been deprecated, and in the latest version of Ocaml (4.06), a compiler flag -safe-string has been enabled by default. This makes string immutable, and the traditional behavior has been moved to a new type called bytes.


Thank you for this concise explanation. This doesn't seem insurmountable at all.


The standard Unicode library in native OCaml is Camomile https://github.com/yoriyuki/Camomile (docs at http://docs.mirage.io/camomile/index.html –unfortunately, it's pretty bare-bones).

If you're targeting JavaScript with Reason/BuckleScript, e.g. making a ReasonReact app, you will automatically get Unicode support for strings if you use the {j|Unicode string literal|j} syntax (specially provided by BuckleScript).


Ah, good to know. Main point is that Unicode is not a problem however cumbersome it might get.


This is a bit of a tangent, but does anyone here know if there exists a JS implementation of Ocaml's Graphics [1] module? I sometimes use Graphics for quick-and-dirty native visualizations, and it would be kind of nice if there were a straightforward way to re-purpose them as Web-based visualizations.

[1] http://caml.inria.fr/pub/docs/manual-ocaml/libref/Graphics.h...


How well does Reason interop with OCaml libraries? Also, how will it work with upcoming changes in the OCaml language that require changes to the runtime (like the multicore runtime, possibly modular implicits)?


Reason is merely a syntax change, it swapped the lexer and parser for its own. The entire rest of the toolchain is the same, so once multicore happens, Reason native will happily leverage it.


started from quickstart and now we're here:

```

let message = "hello";

print_endline message; /* Prints "hello" */

```

output

$ bsb -make-world -w

>>>> Start compiling

Rebuilding since just get started

ninja: Entering directory `lib/bs'

[1/2] Building src/demo.mlast

FAILED: src/demo.mlast

/usr/local/lib/node_modules/bs-platform/lib/bsc.exe -pp

"/usr/local/lib/node_modules/bs-platform/lib/refmt3.exe --print binary" -w -30-40+6+7+27+32..39+44+45+101 -bs-suffix -nostdlib -I '/Users/max/dev_projects/my-first-app/node_modules/bs-platform/lib/ocaml' -no-alias-deps -color always -c -o src/demo.mlast -bs-syntax-only -bs-binary-ast -impl /Users/max/dev_projects/my-first-app/src/demo.re

File "/Users/max/dev_projects/my-first-app/src/demo.re", line 2, characters 15-22:

Error: 2122: syntax error, consider adding a `;' before

File "/Users/max/dev_projects/my-first-app/src/demo.re", line 1, characters 0-0:

Error: Error while running external preprocessor

Command line: /usr/local/lib/node_modules/bs-platform/lib/refmt3.exe --print binary '/Users/max/dev_projects/my-first-app/src/demo.re' > /var/folders/7_/ycch7zrn72b3r_f7sw8lp4v80000gn/T/ocamlpp5f8d7e

---

this is straight from the docs. print_line(message) works fine.


`print_endline message` is version 2 syntax. Could you point me to the exact location so I can send a PR to fix it?


looks like you found it already. somewhere else it said also that compiled js is at lib/js. that's not true anymore (as i'm sure you know it's now at src/name.bs.js)


Can you point to where you got that code from, a URL please. We will fix it so that others won't get errors. Thanks for your help.


print_endline was here but someone already got it:

https://reasonml.github.io/docs/en/let-binding.html

lib/js was here

https://reasonml.github.io/docs/en/quickstart-javascript.htm...

but someone got that one too


Thanks! Appreciate the report :-)




Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact

Search: