Steps
Steps to learning Reason OCaml

Myer Nore
Mar 6, 2018 - 5 min read

Maps

What are Maps?

In many applications it becomes necessary to look up a Record, Object or other data structure by a unique identifier, just as a phone book enables one look up a person's phone number by their name. This structure goes by many names: hashtable, lookup table, hashmap, dict, dictionary, map, etc. There are many tools for this in ReasonML, but two good choices are:

  • Use Map from Reason's OCaml standard API. This is a good general-purpose, performant, immutable dictionary and should probably be the first choice.
  • Use Bucklescript's Object as Hash MapJs.Dict.t. This is is a thin wrapper over the mutable Javascript object. It's a good option you are worried about minimizing your bundle size or are modifying objects that come from JS.

Side Note: Reason & OCaml Standard Libraries

If you go to the Reason docs and search for Map today, you won't find any resources for Map. There are many features in Reason that are supplied by OCaml's standard library, whose docs are accessible on the API tab of the Reason site, though certain elements of the standard API are not currently indexed by the search engine or given much coverage in the standard Reason docs. If you look in the API tab, you'll find Map - Association tables over ordered types is one of API entries, but the API docs can be a little sparse. In cases like this I find it helpful to search for the item in Real World OCaml book or in Stack Overflow's OCaml posts, and then use the Reason Tools browser extension to convert any examples to Reason. See the Links section at the bottom of this post for more information.

Construct a Map From a List

This example declares a new Record type called composer, then constructs a new Map type with String instances as the lookup keys. After we have minted a specialized StringMap Module, we create a getComposerMap function which converts a list of composer types into the StringMap. See the post on Modules in Gradus Reason for more info.

/* loading */

This example is powered by:

  • String, the String module from the Reason OCaml standard API, which is a Module that operates on entities of the string type.
  • List.fold_left, which is The Reason equivalent of Javascript's Array.prototype.reduce. This iterates over an object and accumulates results into another object. Here, we pass the function that will be applied to each element of the list: (map, user) => StringMap.add(user.id, user.name, map). This function that we supply itself takes two parameters. The first parameter (here, map) is the variable to accumulate results in. The second parameter (here, user) is the current object in the iteration:

    List.fold_left(
            (map, user) => StringMap.add(user.id, user.name, map),
            StringMap.empty,
            composers
        )

    This takes the composers array, which is a list of composer types, and executes the supplied folding function (map, user) => StringMap.add(user.id, user.name, map). For the first composer, map is StringMap.empty. For all the other composers, the map parameter is the cumulative result of calling StringMap.add(user.id, user.name, map). At the end of fold_left, the last composer returns the newly filled StringMap.

  • BuckleScript's j string interpolation, which looks like {j|key:$id, val:$composerName|j} and is the equivalent of JS' string interpolation. Here, the $id and $composerName variables are resolved from block scope into a string.
  • Map.Make.find is the method used to get a value by its key. As you can see, the heading for this page says that Map.Make is a "Functor", which in reason is a function that returns a Module. Here, when we did module StringMap = Map.Make(String);, that constructed a new, specific instance of the Map Module that has String map keys. You could think of Map.Make as a constructor for a Module, and the constructed module has the same methods listed in the documentation.

Image Credit: Warburton Post Office Boxes by Mick Stanic on Flickr

Edit this post here