как мне заставить yesod-persistent распознавать тип моего проанализированного массива сущностей aeson?

У меня есть обработчик yesod, который может принимать json с массивом объектов. Я хотел бы вставить все объекты в базу данных.

newtype NodeList = NodeList [Node]

instance FromJSON NodeList where
    parseJSON (Object o) = NodeList <$> o .: "nodes"
    parseJSON _ = mzero

postMoreNodesR :: Handler ()
postMoreNodesR = do
        nodes::NodeList <- requireJsonBody
        runDB $ mapM_ insert nodes
        return ()

Но каким-то образом он не распознает мой тип сущности. (хотя другие обработчики POST и GET в том же модуле работают отлично.) Я могу сказать, что я довольно близок, но я не уверен, что делать, поскольку «a0» не является типом, который я где-либо объявлял. Вот ошибка:

Handler/Node.hs:46:30:
    Couldn't match expected type `[a0]' with actual type `NodeList'
    In the second argument of `mapM_', namely `nodes'
    In the second argument of `($)', namely `mapM_ insert nodes'
    In a stmt of a 'do' block: runDB $ mapM_ insert nodes

person nont    schedule 11.07.2014    source источник


Ответы (2)


Вы также можете сопоставить шаблон непосредственно в привязке:

postMoreNodesR :: Handler ()
postMoreNodesR = do
  NodeList nodes <- requireJsonBody

  runDB $ mapM_ insert nodes

  return ()

Это также устраняет необходимость в аннотации типа.

Это работает, потому что выражение do превращается в лямбду:

requireJsonBody >>= \NodeList nodes -> runDB -- ...
person pbrisbin    schedule 11.07.2014
comment
даже лучше! Я не знал, что внутри блока do можно сопоставлять шаблоны. - person nont; 11.07.2014
comment
На самом деле он не обессахарен до лямбды. Это сложнее, благодаря fail. - person Carl; 11.07.2014

Я понял! Я следил за типами и понял, что мне нужна вспомогательная функция для извлечения узлов из нового списка NodeList:

getNodesFromList :: NodeList -> [Node]
getNodesFromList (NodeList l) = l

Затем моя функция обработчика стала:

postMoreNodesR :: Handler ()
postMoreNodesR = do
        nodes::NodeList <- requireJsonBody
        runDB $ mapM_ insert $ getNodesFromList nodes
        return ()

Этот материал действительно начинает щелкать!

person nont    schedule 11.07.2014
comment
на самом деле, Haskell может автоматически сгенерировать эту функцию для вас :) - person Justin L.; 11.07.2014