#Should I learn Reason or OCaml first?
There's no need to pick! Reason and OCaml share the exact same semantics (i.e. how the code runs). Only the syntax differ. Carry Reason-tools around so that you can freely convert between the two syntaxes. A Reason tutorial is an OCaml tutorial, vice-versa. In the terminal, you can have these aliases:
# converts ocaml code into reason alias mlre="pbpaste | refmt --parse ml --print re --interface false | pbcopy" # converts reason code into ocaml alias reml="pbpaste | refmt --parse re --print ml --interface false | pbcopy"
They'll take your code from the (macOS) clipboard, convert it, and paste it back into your clipboard! Swap out pbpaste/pbcopy with your system's clipboard functions.
#I'm not sure what to do with Reason
#What's the relation between Reason, BuckleScript and OCaml?
#Where do all these
string_of_int functions come from?
They're from the standard library, pre-
opened during the compilation of your file. This is why you see them in scope.
You can read more about the Pervasives library in the api documentation:
#Can I have a function to print arbitrary data structures?
Js.log. If you're compiling to native, you'll need something like ppx_show. A future OCaml feature (called modular implicit) will solve this directly in the language.
#Why is there a + for adding ints and +. for adding floats, etc.?
#Does library ___ work with Reason?
Most JS libraries should easily work under Reason + BuckleScript. On the native side, since Reason's just a syntax transform: yes, they work with Reason too. But the native workflow is currently work-in-progress and needs polish.
#What's the server-side story? Should I compile to native or to JS and use node.js?
We do compile to native, but the native workflow is currently work-in-progress. At this time, we recommend compiling to JS through BuckleScript and use the JS wrappers at reasonml-community or somewhere else.
#What's BuckleScript's async story?
First, if you're not interfacing with any library that uses promises, you can simply use callbacks. Everyone gets them and they're performant.
If you need to bind to a JS library that uses promises, or communicate with such library, you can use BS's Js.Promise. There's also potential to have some syntactic sugar in the future. In the long run, we'd like to implement a spec-compliant promises implementation in OCaml/Reason proper, so that the compiler optimizations could kick in.
#What's the (unit) test story?
Some of OCaml's language features (not just types) might be able to defer the need for unit testing until later. In the meantime, for compilation to JS, we're working on Jest wrapper. We'll look into using Jest for native too, if Jest is written using Reason in the future (no concrete plan yet). OUnit is a good, small native OCaml testing library right now.
.merlin file at the root of my project?
That's the metadata file for editor support. This is usually generated for you; You don't need to check that into your version control and don't have to manually modify it.
#I don't see any
require in my file; how does module resolution work?
Reason/OCaml doesn't require you to write any import; modules being referred to in the file are automatically searched in the project. Specifically, a module
Hello asks the compiler to look for the file
hello.ml (and their corresponding interface file,
hello.mli, if available).
A module name is the file name, capitalized. It has to be unique per project; this abstracts away the file system and allows you to move files around without changing code.
Some | None,
List and all of these special? Where do they come from?
They're ordinary variants/records/module definitions that come with the standard library,
opened by default during compilation out of convenience.
#What does an argument with a prepended underscore (e.g.
Say you have
List.map(item => 1, myList);. The argument
item isn't used and will generate a compiler warning. Using
_ => 1 instead indicates that you're intentionally receiving and ignoring the argument, therefore bypassing the warning. Alternatively,
_item => 1 has the same effect, but indicates more descriptively what you're ignoring.
MyModule.t I keep seeing?
MyModule is a module's name,
t is a community convention that indicates "the type that represents that module, whatever that means". For example, for the
String.t is the type carried around and representing "a string".
#Why is there a
Js_promise and then a
Js.Promise? What about
Js_string and whatever else?
As a convention,
Js_foo is the actual module, and
Js.Foo is just an alias for it. They're equivalent. Prefer
Js.Foo, because that's the official, public module name.
#When will modular implicit & multicore & algebraic effects be ready?
They will one day. In the meantime, help us ship more Reason code! The popularity will help funnel more OCaml contributions. The less the OCaml folks need to worry about low-hanging fruits, the more they can focus on great research and execution!
#Why are BuckleScript and bsb so fast? How can I slow it down?
BuckleScript is optimized for performance across the whole stack. You can try slowing it down by adding a dozen layers of indirections and metaprogramming. Try:
Adding a few infinite loops here and there.
Dragging in more dependencies for writing a hello world.
#I'm seeing a weird .cmi/.cmx/.cmj/.cma file referenced in a compiler error. Where do these files come from?
.ml: OCaml source file
.mli: OCaml interface file; determines which parts of the matching
.mlfile are visible to the outside world
.re: Reason source file. Like
.ml, but for Reason
.rei: Reason interface file. Like
.mli, but for Reason
.cmi: Compiled interface (.rei/mli) file
.cmx: Compiled object file for native output (via ocamlopt)
.cmo: Compiled object file for bytecode output
.cmj: Compiled object file for web (via BuckleScript)
.cma: Library file for bytecode output (equivalent to C's .a files)
.cmxa: Library file for native output
.cmt: Contains a "Typedtree" – basically the AST with all type info
.cmti: Just like a .cmt file, but for interface files
.cmxs: Dynamically loaded plugin (for native compilation)
.o: Compiled native object file
.out: Conventional name/extension for final output produced by ocamlc/ocamlopt (e.g.
ocamlc -o myExecutable.out)
#Other OCaml ecosystem files
.mll: ocamllex lexical analyzer definition file
.mly: ocamlyacc parser generator definition file
.mldylib: Contains a list of module paths that will be compiled and archived together to build a corresponding
.cmxstarget (native plugin)
.mliv: Batteries-specific files for some custom preprocessing.
.mllib: OCaml library (cma and cmxa)
.mlpack: OCaml package (cmo built with the -pack flag)
.mlpp: Extlib-specific files for some custom preprocessing
.mltop: OCamlbuild top-level file, used by OCamlbuild to generate a .top file
.odocl: OCaml documentation file
If some of those explanations are still a bit cryptic, here are expansions on some of the terms used above:
AST: Abstract Syntax Tree. The data structure coming from the source code, that the compiler operates on.
Linking: The step where the compiler takes many intermediate compiled files and assembles them together. E.g. linking A with B, because A's original source file referred to B.
Native: Builds that run on bare metal assembly instructions of the platform in question.
Bytecode: Like native code, but more portable and less performant
Object file: Contains machine code that is not directly runnable.
There is more information and context for many of these file extensions on the OCaml site and in this mailing list post. There are also deeper dives on native and bytecode compilation that contain more detailed descriptions in the OCaml manual.