I am trying to use Maybe in Purescript. I have a simple function like this:
getName :: { name :: Maybe String} -> String
getName { name: Just x } = x
getName { name: Nothing } = "No name"
And a JS object like this:
const example = {
name: 'Hello'
}
when I run getName(example)
, it returns error:
Error: Failed pattern match at Utilities (line 53, column 1 - line 53, column 45): Object
I guess I have to lift the value of name up in example first in order for this to work? If I need to set it Just
or Nothing
by checking if any value exists there, is using isUndefined
the way to go? Checking undefined
in Purescript looks like how I would code in JS, thus I want to know if there is a better approach for this.
Well, the most idiomatic way of dealing with this in the PureScript side depends somewhat on your context. Are you working with data coming in from the FFI? The most typical thing to do there is to make your foreign .js file “sanitize” the types, by providing Just
and Nothing
to the JS code. So you might see something like
exports.getExample = function(Just) {
return function (Nothing) {
if (example.name === undefined) return { name: Nothing };
else return { name: Just(example.name) };
};
}
and then on the PureScript side, that would look like
foreign import getExample :: (String -> Maybe String) -> (Maybe String) -> { name :: Maybe String }
example :: { name :: Maybe String }
example = getExample Just Nothing
(Probably you’d actually use Fn2
and make the JS function uncurried).
Maybe you’re trying to decode some JSON value that might be null. In our code, we use argonaut, and we’ll have something like this:
newtype JsonMaybe a = JsonMaybe (Maybe a)
instance decodeJsonMaybe :: DecodeJson a => DecodeJson (JsonMaybe a) where
decodeJson json
| isNull json = Right (JsonMaybe Nothing)
| otherwise = do
x <- decodeJson json
pure (JsonMaybe (Just x))
which lets us decode something like the example object in your code like
type Example = { name :: Maybe String }
type ExampleJson = { name :: JsonMaybe String }
decodeExample :: Json -> Either String Example
decodeExample json = case decodeJson json of
Right ({ name :: JsonMaybe name } :: ExampleJson) -> Right { name }
Left err -> Left err
(I’m a little annoyed that there isn’t an isUndefined
in Argonaut, only isNull
, so you’d have to build that yourself).
Are you able to share a bit more about your context?
Both the FFI and working with untyped JSON values are considered “advanced” concepts in PureScript, so don’t feel aggrevated if it gets really deep really fast - just hang in there!
I think the js side could also work like:
exports.getExample = Just => Nothing => ({ name: example.name === undefined ? Nothing : Just(example.name) })