Reputation: 300
Consider the following code:
S.get "/budget/:bid/month/:mnth" $ do
mbid <- param "bid"
(budget :: Maybe Budget) <- liftIO $ getBudget $ toSqlKey mbid
(categories :: [Entity Category]) <- liftIO $ getCategories $ toSqlKey mbid
case budget of
Nothing -> json $ object [ "message" .= ("No budget was found!" :: String) ]
Just b -> do
json $ object [
"categoryExpenditures" .= map (\x -> object ["spent" .= liftIO $
calculateCategoryBalanceForMonth (entityKey x) 1 >>= (\y -> y) ]) categories
]
Up until this point, calculateCategoryBalanceForMonth
has type calculateCategoryBalanceForMonth :: CategoryId -> Int -> IO Double
.
I am attempting to map over categories
and return a list of categoryExpenditures
as a JSON object in Aeson. However, I cannot figure out how to return the value from liftIO
to the .=
operator.
My attempt involved desugaring the assignment operator to >>= (\y -> y)
or >>= id
where I was hoping id
would return a Double, or at least something that had an instance of ToJSON
. This does not appear to be the case though.
I also know that using the assignment operator for the liftIO
expression, and then passing the assigned variable into the .=
operator works, however I was unsure how to use the assignment operator within an anonymous function for map.
What might I be doing wrong? Is any more clarity needed?
Upvotes: 0
Views: 59
Reputation: 180
I'm assuming you're working with a monad stack with IO
at the bottom.
object
takes [Pair]
as argument, however you're trying to pass it an IO
. (>>=)
keeps things inside the monad (by definition!), so (>>= id)
does not do what you want it to (in fact, the signature of (>>= id)
is Monad m => m (m a) -> m a
, ergo join
). You want to move things around a bit:
Just b -> do
expenditures <- forM categories (\x -> do
spent <- liftIO $ calculateCategoryBalanceForMonth (entityKey x) 1
return $ object [ "spent" .= spent ])
json $ object [ "categoryExpenditures" .= expenditures ]
For mapping with a monadic result, use mapM
, or forM
(forM = flip mapM
).
Upvotes: 2