Ps-inline-asm: interpolate Javascript into Purescript source

TL;DR: I wrote a tool for javascript interpolation (inline asm); find it here.

Howdy, all!

I absolutely love Purescript, but I’ve always felt that the FFI is a little bit inflexible. I often find myself writing one-off single-line foreign functions, such as:

foreign import getByIdAndSetFocus :: String -> Effect Unit

Implemented as:

exports.getByIdAndSetFocus =
    id => () => document.getElementById(id).focus();

And used like:

do
  myId <- calcId
  getByIdAndSetFocus myId

Using the FFI for these one-off cases feels very clunky to me. I need to modify three lines across two files in order to implement what is morally a one-liner. (To be fair, I don’t think the FFI is intended to be used this way, but I am choosing to do so anyway. :wink:)

To aid with these cases, I created a tool called ps-inline-asm to allow for more flexible FFI usage. It supports emedding arbitrary javascript expressions within purescript code, and even interpolation between the two languages.

Using ps-inline-asm, I could rewrite the above example as just:

do
  myId <- calcId
  asm " () => document.getElementById(#{myId}).focus() "

Then ps-inline-asm would compile this into a foreign import and foreign module on my behalf.

I’m already using this tool in one of my projects, and am announcing its existence to the Purescript community in case anybody else finds it useful. It’s not production-ready right now, but I’m happy to continue working on it if people find it useful.

Enjoy!

4 Likes

Looks really nice! I would definitely use it if it got any support from, let’s say, vscode plugin. I understand that until I run ps-inline-asm manually, the call site would be highlighted as an error variable asm not in scope. But if it emitted an error like “compile to foreign code” and display an available vscode code action that would trigger the tool, this thing would rock.

Edit: even better, going forward I’d like just to write
let pow = asm "x => y => Math.pow(x,y)" :: Number -> Number -> Number
without needing to run the tool and the editor / compiler won’t complain. But that would require some compiler plugin API as in GHC (is there any? I think not)

Edit 2: I think that we could just define asm :: forall a. String -> a and use your tool as a, for instance, webpack plugin. I think that would work out-of-the-box.

Thanks for the comments!

An even more one-size-fits all solution would be to publish a package on Pursuit which defines Foreign.Asm (asm) with the type you gave. Then all you need is access to Purescript packages in your toolchain!

First-class editor plugins could of course be more featureful, for instance providing analysis of interpolated expressions, and recognizing that asm is not actually a function but a syntactic construct. But Foreign.Asm is probably a good place to start.

1 Like

Yep, that’s what I thought about in edit 2 :slight_smile:

1 Like

Oops! Apologies, I had misunderstood what you meant