3
votes

I'm trying to call the navigator.geolocation.getCurrentPosition javascript function from purescript, but I've come across two problems.

In javascript it would be called using something like

navigator.geolocation.getCurrentPosition(function(position) { ... });

where position is an object.

Firstly, I don't know what the return type should be as it doesn't return anything, but instead calls a callback.

Secondly, I don't know what type to use for the callback, as the function can't be pure as it's result won't be returned.

So far I have

foreign import geolookup "function (callback) {\
        navigator.geolocation.getCurrentPosition(callback);
    \}" :: forall eff a. Eff (geolookup :: GeoLookup | eff) {}

geolookup \position -> ...

So here my type signature for the foreign function is forall eff a. Eff (geolookup :: GeoLookup | eff) {}, however I know there should be a callback paramter in there too before the Eff. I'm just not sure how to write the type signature or implement it.

1

1 Answers

8
votes

Firstly, I don't know what the return type should be as it doesn't return anything, but instead calls a callback.

You've correctly identified the return type as Unit, or {}, but the geolookup function itself is effectful, so should be wrapped with the Eff type constructor.

Secondly, I don't know what type to use for the callback, as the function can't be pure as it's result won't be returned.

So let's give the callback an appropriate type. As an effectful function, something like a -> Eff _ b makes sense, and to avoid duplicate labels in rows, we're forced to include the GeoLookup effect in our row. So let's give the callback the type Position -> Eff (geolookup :: GeoLookup | eff) Unit.

Then the full type of our function becomes

foreign import data Position :: *

geolookup :: forall eff. (Position -> Eff (geolookup :: GeoLookup | eff) Unit) ->
                         Eff (geolookup :: GeoLookup | eff) Unit

In the FFI, we can wrap the navigator.geolocation.getCurrentPosition call to be compatible with this type. Using the FFI style from the 0.7 compiler:

exports.geolookup = function(callback) {
  return function() { // Outer Eff
    navigator.geolocation.getCurrentPosition(function(p) {
      callback(p)(); // Extra () due to inner Eff
    });
  };
};

At this point, you might like to look into types like ContT or Aff to wrap up your function in a more composable way.

You might like to read the article on how to use the Eff monad.