FFI

Module names

A module MyModule.purs with the below definition will compile to the Erlang module myModule@ps. Note the camelCasing and the suffix of @ps added to the module name.

module MyModule where

A module MyModule.purs with the below definition will compile to acmeCorp_myModule@ps. Note the underscore between namespaces, as well as the camelCasing per namespace and the eventual suffix of @ps.

module AcmeCorp.MyModule where

These details are important when writing foreign function imports in Erlang, the means of doing so being to create an Erlang module next to the Purescript module, with the same name but with a .erl suffix. MyModule.purs therefore would have a corresponding MyModule.erl if we wanted to do FFI.

The name of the compiled module comes into play, as the Erlang module requires an appropriate name to go with it.

  • MyModule.purs with module MyModule in Purescript would have a foreign import module of MyModule.erl containing -module(myModule@foreign) in Erlang
  • MyModule.purs with module AcmeCorp.MyModule in Purescript would have a foreign import module of MyModule.erl containing -module(acmeCorp_myModule@foreign) in Erlang

Foreign Function Imports

Having defined a Purescript module with an appropriately named Erlang module side by side, the next thing would be to define a function in Erlang that we can call from Purescript.

-module(myModule@foreign).

-export([ add/2 ]).

add(X,Y) -> X + Y.

To create a function that’s callable from Purescript, we need to import this as a foreign function in our Purescript module. This can be exported from the module just like any other function at that point.

module MyModule ( add )
  where

foreign import add :: Int -> Int -> Int

In general where we have legacy Erlang of the form my_module:do_stuff, we’d be creating MyModule.purs and MyModule.erl and defining functions that map onto that legacy API, and thus we can interact with our existing code in a reasonably safe manner.