说我有以下模型:

Person
    stackOverflowUser Bool
    age Int Maybe


使用Esqueleto(&Yesod),说我想获得Stack Overflow用户的平均年龄。我想使用类型签名创建一个函数:

userAge :: Handler (Maybe Int)


到目前为止,我有以下内容:

userAge :: Handler [Value (Maybe Int)]
userAge = runDB $
    select $
    from $ \person -> do
    where_ (person ^. PersonStackOverflowUser ==. val True)
    return joinV $ avg_ (person ^. PersonAge)


那让我[值(也许是整数)],但是我需要深入到“也许是整数”。我试着做

mapM_ unValue userAge


但是出于某种原因,这样做会引发类型错误,给我[Maybe()]而不是[Maybe Int] ...另外,我认为上述代码的最后一行应该具有:

person ?. PersonAge


而不是

person ^. PersonAge


因为PersonAge可以为NULL,但是更改它会导致类型错误,因为:

avg_ :: (PersistField a, PersistField b) => expr (Value a) -> expr (Value (Maybe b))
(^.) :: (PersistEntity val, PersistField typ) => expr (Entity val) -> EntityField val typ -> expr (Value typ)
(?.) :: (PersistEntity val, PersistField typ) => expr (Maybe (Entity val)) -> EntityField val typ -> expr (Value (Maybe typ))


这可能比我想像的要容易,但是在网上找不到在Esqueleto中使用聚合函数的示例,而且对于Haskell来说我还很陌生,因此我很难弄清楚它。

我想我可以只使用原始SQL,但如果可能的话,我想使用Esqueleto进行此操作。

最佳答案

得到它了!最终,我把头放在类型错误周围,并提出了以下建议:

import Safe (headMay)
import Control.Monad (join)
import Database.Esqueleto
-- other misc Yesod imports

userAge :: Handler (Maybe Int)
userAge = do
    a <- runDB $ select $
                 from $ \person -> do
                 where_ (person ^. PersonStackOverflowUser ==. val True)
                 return $ joinV $ avg_ (person ^. PersonAge)
    return $ join (headMay (map unValue a))


“ person ^。PersonAge”似乎没有引起任何问题;我在null和非null值上对其进行了测试。我想是“?”。运算符保留给其他情况。

希望这可以节省其他人弄清楚的时间!

10-08 08:46