Не знаете, как присвоить монадическое значение паре Aeson

Рассмотрим следующий код:

    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 и вернуть список categoryExpenditures в виде объекта JSON в Aeson. Однако я не могу понять, как вернуть значение из liftIO в оператор .=.

Моя попытка заключалась в понижении сахара оператора присваивания до >>= (\y -> y) или >>= id, где я надеялся, что id вернет Double или, по крайней мере, что-то, что имело экземпляр ToJSON. Однако, похоже, это не так.

Я также знаю, что использование оператора присваивания для выражения liftIO, а затем передача назначенной переменной в оператор .= работает, однако я не знал, как использовать оператор присваивания в анонимной функции для карты.

Что я могу делать неправильно? Нужна ли еще какая-то ясность?


person acrognale    schedule 04.02.2016    source источник
comment
Не могли бы вы опубликовать автономные фрагменты кода или хотя бы несколько подписей? Невозможно читать haskell без подписи под рукой. Насколько я понимаю, вы пытаетесь выполнить ввод-вывод во время преобразования в JSON?   -  person bash0r    schedule 04.02.2016


Ответы (1)


Я предполагаю, что вы работаете со стеком монад с IO внизу.

object принимает [Pair] в качестве аргумента, однако вы пытаетесь передать ему IO. (>>=) хранит вещи внутри монады (по определению!), поэтому (>>= id) не делает того, что вы хотите (на самом деле, подпись (>>= id) - это 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 ]

Для сопоставления с монадическим результатом используйте mapM или forM (forM = flip mapM).

person Narvius    schedule 04.02.2016