How to write an FFI function returning Maybe?

ffi

#1

adius [6:27 AM]
How can I implement such a function: foreign import doSomething :: String -> Maybe Number ?

justinw [6:28 AM]
you have to give the constructors to the JS also
(a -> Maybe a) and (Maybe a), Just and Nothing
otherwise you can choose to return foreign and just return either the read result or Nothing on both Nothing and a parse failure

bklaric [6:42 AM]
FWIW what I do is write:

foreign import doSomethingImpl :: String -> Nullable Number
doSomething = doSomethingImpl >>> toMaybe

because dealing with PureScript values like Maybe in JavaScript is not nice.

adius [7:03 AM]

dealing with PureScript type constructors like Maybe in JavaScript is not nice

That’s what I thought :sweat_smile:
Cool, exactly what I was looking for! Thanks @bklaric

bklaric [7:05 AM]
You’re welcome.

gabejohnson [8:55 AM]
@adius, @justinw was saying

foreign import doSomethingImp :: forall a. (a -> Maybe a) -> Maybe a -> String -> Maybe Number

doSomething :: String -> Maybe Number
doSomething = doSomethingImpl Just Nothing

You could also replace a with Number if you wanted.
But toMaybe essentially does ^


#2

It’s slightly better to implement it like this:

foreign import doSomethingImp :: (forall a. a -> Maybe a) -> (forall a. Maybe a) -> String -> Maybe Number

(moving the foralls into the constructors)
As it reduces the number of possible implementations for the passed-in Just/Nothing such that they’re basically the only allowable arguments.

There used to be a section in the FFI docs about this technique, but I guess it was deleted at some point after transitioning off the wiki?


#3

How does that work? I would have thought that the first argument could be Just or const Nothing and the second argument would have to be Nothing in either case.


#4

Not quite: consider

foreign import lol :: forall a. (a -> Maybe a) -> Maybe a -> Something

which can be called like

lol (Just <<< (_ + 1)) (Just 0)

By putting the forall right at the beginning, you’re saying the caller is allowed to pick any type a, and the implementation has to be able to deal with that (no matter what they pick). If you put it inside the individual arguments it’s the other way around: you’re saying that the implementation is allowed to pick any type a to use those arguments with, and whatever the caller supplies has to work with any possible choice of a.


#5

Yeah, that’s what I was getting at. I perhaps should have provided an example along those lines :slight_smile: