不确定如何将 monadic 值分配给 Aeson 对

Unsure how to assign monadic value to Aeson pair

考虑以下代码:

    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 和 return 的 categoryExpenditures 列表映射为 Aeson 中的 JSON 对象。但是,我无法弄清楚如何 return 从 liftIO.= 运算符的值。

我的尝试涉及将赋值运算符脱糖为 >>= (\y -> y)>>= id,我希望 id 会 return 一个 Double,或者至少有一个实例ToJSON。不过,情况似乎并非如此。

我也知道对 liftIO 表达式使用赋值运算符,然后将赋值的变量传递给 .= 运算符是可行的,但是我不确定如何在一个表达式中使用赋值运算符地图的匿名函数。

我可能做错了什么?还需要更清楚吗?

我假设您正在使用底部 IO 的 monad 堆栈。

object[Pair] 作为参数,但是您试图将其传递给 IO(>>=) 将东西 保留在 monad 中(根据定义!),所以 (>>= id) 不会按照你的意愿去做(事实上, [=16 的签名=] 是 Monad m => m (m a) -> m a,因此 join)。您想稍微移动一下:

Just b -> do
      expenditures <- forM categories (\x -> do
          spent <- liftIO $ calculateCategoryBalanceForMonth (entityKey x) 1
          return $ object [ "spent" .= spent ])
      json $ object [ "categoryExpenditures" .= expenditures ]

对于具有一元结果的映射,请使用 mapMforM (forM = flip mapM)。