As you correctly note, you need to construct a Year
, Month
, and Day
to use exactDate
. These types can’t be constructed directly from numbers, because then you would be able to construct invalid values. The docstring you copy-pasted says:
The toEnum function can be used to safely acquire a year value from an integer.
You can search the toEnum
function: https://pursuit.purescript.org/search?q=toEnum
toEnum :: forall a. BoundedEnum a => Int -> Maybe a
This means that given an Int
, you get a Maybe Year
, which is a year or nothing. The same toEnum
function can in fact be used to construct also a Day
and a Month
, because the BoundedEnum
instance is also listed in the docs of Day
and Month
. The final Date
construction from integers could look something like this:
makeDate :: Int -> Int -> Int -> Maybe Date
makeDate year month day = case toEnum year of
Nothing -> Nothing
Just y -> case toEnum month of
Nothing -> Nothing
Just m -> case toEnum day of
Nothing -> Nothing
Just d -> exactDate y m d
I didn’t need to construct a Month
from a number, I could have used a month constructor instead.
This function can be used in your code, again, using pattern-matching to isolate the construction failure:
case makeDate 2021 1 5 of
Nothing -> log "Provided numbers don't form a valid date."
Just date -> log ("Success. The date is: " <> show date)
The code for makeDate
is very repetitive and nested, so there are some ways to make it shorter.
The problem is that each step may fail, and we handle each failure separately. Ideally, you would handle the construction failure only once (when pattern matching on the resulting Maybe Data
), and short-circuit all the Nothing
s which could be created on the way to return Nothing
immediately.
The do-notation is a convenient way to do just that:
makeDate :: Int -> Int -> Int -> Maybe Date
makeDate year month day = do
y <- toEnum year
m <- toEnum month
d <- toEnum day
exactDate y m d
Or you can use applicative composition operators. This takes some practice to be comfortable with:
makeDate :: Int -> Int -> Int -> Maybe Date
makeDate year month day =
join $ exactDate <$> toEnum year <*> toEnum month <*> toEnum day
or the same thing, using slightly different combinators:
makeDate :: Int -> Int -> Int -> Maybe Date
makeDate year month day =
join $ lift3 exactDate (toEnum year) (toEnum month) (toEnum day)
To sum up, in Purescript, all failures must be handled. You normally don’t have functions which would throw an exception or create illegal state when the input is bad. Failures are instead indicated by returning a Nothing
, or some other “error” value. Working with these comfortably requires some extra plumbing, such as the do-notation.
EDIT: to work with Javascript dates, you can use the JSDate type: https://pursuit.purescript.org/packages/purescript-js-date/7.0.0/docs/Data.JSDate#t:JSDate . JSDate
can be converted to Date
or DateTime
using the provided functions.