Facade for js class

Hello everyone,

I’m new to purescript and relatively new to the functional world. I’m interested in using purescript to generate javascript code. So I have some basic doubts about interoperability with javascipt. In my tests, I wanted to use a javascript class in my purescript code, something common if I use JS libraries or framework. I didn’t find exactly how to do this, since the documentation suggested on the official website apparently doesn’t have any example of this. I managed to do it through trial and error. I wanted to know if the solution is correct or if there is a better way to do this. Here is my code:

JS LIB

class MyMath {
    sum(x, y){
        return x + y
    }
}

function divide(x, y) {
    return x / y
}
            

JS.js → Module to purs

"use strict";

export const _divide = divide;

export const _MyMath = MyMath;

export const _newMath = () => new MyMath()

JS.purs → Facede pure


module JS.MyMath
   ( divide
   , newMath
   , MyMath
   )
   where

import Prelude
import Data.Function.Uncurried (Fn0, Fn2, runFn0, runFn2)

-- js class facede
type MyMath = {
     sum :: Fn2 Int Int Int
}

foreign import _divide :: Fn2 Int Int Int

foreign import _newMath :: Fn0 MyMath

divide :: Int -> Int -> Int
divide x y = runFn2 _divide x y

newMath :: MyMath
newMath = runFn0 _newMath

Main.purs

module Main
   ( main
   , ns
   )
   where

import Prelude

import Data.Function.Uncurried (runFn2)
import Effect (Effect)
import Effect.Console (log)
import JS.MyMath (MyMath, divide, newMath)

main :: Effect Unit
main =
   let
     s = m.sum
     r = runFn2 s 10 10
  in do
     log $ "divide " <> (show $ divide 10 5)
     log $ "math sum " <> (show r)

Is there any way to create an instance of MyMath directly in pure code? With I couldn’t, I ended up creating a factory function that creates an instance.

Thanks in advance for the tips!

…is the standard way to create JS class instances from PureScript. Representing JS classes using PS types is not guaranteed to always work the same way in future PS versions (which is why it isn’t documented); instead, you should foreign import data MyMath :: Type and expose any functionality on MyMath—instance creation and methods alike—as plain functions that accept/return MyMath values, as described here.

Hi @rhendric ,

Thanks for the answer! I’m not very familiar with the language yet, could you give an example of how I would use this? If I declare foreign import data MyMath :: Type how would I know that MyMath has a function called sum? How do I bind this with type MyMath?

Typically, your JS FFI code would contain

export const sum = myMath => x => y => myMath.sum(x, y);

and the PS code for the same module would contain

foreign import data MyMath :: Type -- doesn't bind anything, just tells the PS compiler to believe that an opaque type called MyMath exists
foreign import sum :: MyMath -> Int -> Int -> Int
2 Likes

Now it’s clearer! Thanks for the help =)

1 Like