Lots of things are very nice in Elm but occasionally you find a gap. For me, currency formatting was such a gap. It’s non-trivial enough to be annoying if you need to deal with different locales and different currencies. Javascript has a perfect api for this in the form of the toLocaleString function.
Elm has an undocumented feature called Native modules allowing you to call javascript functions directly. Of course this is a bad idea and can easily re-introduce all of the type chaos and runtime errors that you were trying to escape. But in a case like this it seems reasonable — why reinvent a perfectly good api?
The information I was able to find about how to do this was a little out of date and that’s why I’m writing up how it can be done in Elm 0.18.
First step is to create a normal Elm module to expose your function.
module Utils.CurrencyFormat exposing (format)
--this is where we import the native moduleimport Native.CurrencyFormat
format : String -> String -> number -> Stringformat culture currency num =letres =Native.CurrencyFormat.format culture currency numincase res ofOk str ->str
Err err ->
let
\_ =
Debug.log "CurrencyFormatError" err
in
toString num
Next create a js file called /src/Native/CurrencyFormat.js. Now, once again, this is not safe so do everything you can to make this js function bullet-proof.
var _user$project$Native_CurrencyFormat = (function () {
var format = function(cultureCode, currency, num) {
try {
var result = num.toLocaleString(cultureCode, {style: 'currency', currency: currency});
return {
ctor: "Ok",
\_0: result
};
} catch (e) {
return {
ctor: "Err",
\_0: e.message
};
}
};
return {
format: F3(format)
};
})();
This will expose this function to Elm to be called from the module we created in step one. Notice a couple of things: toLocaleString can fail if we give it bad inputs. For this reason we wrap the call in try catch and we return the result as an Elm (Result String String) by supplying the constructor of either Ok or Err. We could choose to pass that result on to the calling code or handle it in our utility function as I have done by just logging it and returning a plain stringified number. It depends how important the error is to you.
The second thing to note is that I am wrapping the returned function in a call to a mystery F3 function. I am guessing a little bit here, but I’m pretty sure this ensures that the function is appropriately curried so that partial application will work as expected on the Elm side.
Make the following small change to your elm-package.json file
{"version": "1.0.0","summary": "","repository": "https://github.com/user/project.git","license": "BSD3","source-directories": ["./client/elm"],"native-modules": true,"exposed-modules": [],"dependencies": {"elm-lang/core": "5.0.0 <= v < 6.0.0","elm-lang/html": "2.0.0 <= v < 3.0.0","elm-lang/http": "1.0.0 <= v < 2.0.0"},"elm-version": "0.18.0 <= v < 0.19.0"}
Your function should work just like a normal Elm function if you’ve done everything right. It will even support automatic currying like any other Elm function. Try it out …
toCurrency : number -> StringtoCurrency =Currency.format "en" "GBP"
I think that in some limited circumstances this is a good solution. But beware, this is an undocumented feature and it can change and be broken at any time so use it at your own risk.
Hacker Noon is how hackers start their afternoons. We’re a part of the @AMIfamily. We are now accepting submissions and happy to discuss advertising & sponsorship opportunities.
To learn more, read our about page, like/message us on Facebook, or simply, tweet/DM @HackerNoon.
If you enjoyed this story, we recommend reading our latest tech stories and trending tech stories. Until next time, don’t take the realities of the world for granted!