Saturday, June 10, 2023

A quick look at functors in OCaml

A couple of weeks ago I was working on a small program that required generating code in different ways depending on a user option. I was trying to make as few changes as possible. Because of the way the program was created and the language it was written in (not OCaml), it required changing several places in the code.

OCaml functors

I remembered reading a little bit about the concept of a functor in OCaml. Functors are a powerful mechanism that allow you to create modules parameterized by modules. In the case of the task I was working on, I can use it to write the code generation section using module parameterized by a module that provides the final implementation of the code generation.

The example: Code generation via method calls or operators

I’m going to use a simple example of using a functor. Say that we have a representation for a very simple language:

I want to have the posibility of generating arithmetic expressions in this language in two ways:

  1. Generating method calls of arithmetic operations for a Java-like language
  2. Generate common operators

One example of option #1 is:

var1.multiply(10).plus(var2)

For option #2 is:

var1 * 10 + var2

The code that generates the expressions must not be aware of the strategy that we are using to generate the code. To do this in OCaml we define a signature for the module used to generate the code:

We use operators to make it easy to write the code generation. The module that makes the code generator is written as a functor with a parameter that is the module which implements the GeneratorFuncs signature.

The following code shows the “generator” which generates random arithmetic expressions using the provided module for emitting the code:

We can write our emitter for generating code using method calls like this:

An alternative module that generates arithmetic expression using operators:

We can use this modules to generate sample code snippets:

Output:

x.plus(2).plus(5.div(4)).div(x.plus(x).plus(5.div(1)))
x + 4 / x - 2 + 4 + x + 5 + x

Sunday, June 4, 2023

Haskell 'newtype' and the record syntax

While reading some Haskell code snippets I found something that seemed confusing. The snippet involved newtype and record syntax. A simplified example is the following:

newtype PersonName = PersonName { theName :: String }
...
let p1 = PersonName $ getName obj
in print $ theName

I was not able to find a place where the PersonName was created by specifying the value of theName explicitly for example (Person { theName = "xyz" }) . The reason is that record syntax allows an alternative way of specifying the field values. For example:

let p1 = PersonName "Luis" -- valid!
...
let p2 = PersonName { theName = "Luis" }  -- valid!

Another thing that I found interesting is the newtype restrictions. For example it only allows you to specify one field in our record:

newtype PersonName' = PersonName' { firstName :: String, lastName ::String }

Compiling this is going to generate the following error:

newtypeexp.hs:6:23: error:
    • The constructor of a newtype must have exactly one field
        but ‘PersonName'’ has two
    • In the definition of data constructor ‘PersonName'’
      In the newtype declaration for ‘PersonName'’
  |
6 | newtype PersonName' = PersonName' { firstName :: String, lastName ::String }
  |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

This seems to be related to the fact that newtype is used as a compile-type concept only. More info here https://wiki.haskell.org/Newtype#The_short_version .