请考虑以下代码:
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
]
到目前为止,calculateCategoryBalanceForMonth
的类型为calculateCategoryBalanceForMonth :: CategoryId -> Int -> IO Double
。
我正在尝试映射categories
并在Aeson中返回categoryExpenditures
列表作为JSON对象。但是,我无法弄清楚如何将值从liftIO
返回给.=
运算符。
我的尝试涉及将赋值运算符移至>>= (\y -> y)
或>>= id
,我希望id
返回Double,或者至少有ToJSON
实例的东西。但情况似乎并非如此。
我也知道使用liftIO
表达式的赋值运算符,然后将赋值的变量传递给.=
运算符,但我不确定如何在匿名函数中使用赋值运算符对于地图。
我可能做错了什么?需要更清晰吗?
答案 0 :(得分:2)
我假设您正在使用底部为IO
的monad堆栈。
object
以[Pair]
为参数,但您尝试将IO
传递给(>>=)
。 (>>= id)
将内的保留在 monad中(根据定义!),因此(>>= id)
不会按照您的意愿执行(事实上,Monad m => m (m a) -> m a
的签名是join
,ergo Just b -> do
expenditures <- forM categories (\x -> do
spent <- liftIO $ calculateCategoryBalanceForMonth (entityKey x) 1
return $ object [ "spent" .= spent ])
json $ object [ "categoryExpenditures" .= expenditures ]
)。你想稍微改变一下:
mapM
要使用monadic结果进行映射,请使用forM
或forM = flip mapM
(required
)。