在 esqueleto 中乘以 Int 和 double 值?

Multiplying Int and double values in esqueleto?

我面临的问题非常简单:基本上我正在尝试计算 Int 和 Double 的乘积。简单地说 Haskell 我会 运行

product = (fromIntegral int_val) * double_val

但是我不知道如何在 esqueleto 中做到这一点。我有一个 table B,它有一个 Int 类型的列 "amount" 和一个 table C,它有一个 Double 类型的列 "price"。当尝试提取两者并计算乘积时,像这样

(b ^. BAmount) *. (c ^. CPrice) 

我遇到类型错误(如预期):

Couldn't match type ‘Double’ with ‘Int’
Expected type: EntityField Drink Int
  Actual type: EntityField Drink Double

我在文档中找不到任何对我有帮助的东西,我实际上不知道如何继续。 (有关更多代码,请参阅下面的完整示例)。

可能的解决方案:我当然可以将价格存储为 Int,但我很想知道这是否可以用 esqueleto 完成。

完整示例:

数据库:

Table答:身份证|姓名

Table B: Id|AId|BId|金额 其中 Amount 是 Int,AId 和 BId 是对 Table A 和 B 的引用。

Table C: Id|Name|Price , 这是双人间价格

我写的查询如下:

result <- liftIO $ runDb $ select $
            from $ \(a, b, c) -> do
              where_ (a ^. AId ==. b ^. BAId)
              where_ (b ^. BCId ==. c ^. CId)
              let product = (b ^. BAmount) *. (c ^. CPrice)
              let total = sum_ product :: SqlExpr (Value (Maybe Double))
              groupBy $ a ^. AName
              return (a ^. AName)

编辑:

我试过像这样使用 fmapfromIntegral

let product = fmap fromIntegral (b ^. BAmount) *. (c ^. CPrice)

这会导致两个错误: No instance for (Functor SqlExpr)No instance for (Num (Value Double))

按照评论中的建议(@Thomas M. DuBuisson),我试过:

let product = fmap (fmap fromIntegral) (b ^. BAmount) *. (c ^. CPrice)

这解决了第二个问题,但我仍然得到 No instance for (Functor SqlExpr).

编辑 2:

我已经在 Yesod 邮件列表中询问过这个问题。讨论可见here.

我不是专家,但您可以尝试将 _floor 应用于您的 整数 参数:

floor_ :: (..., PersistField a, Num a, PersistField b, Num b)
       => expr (Value a) -> expr (Value b)

这可能会将您的整数转换为双精度整数,因为 ab 可能不同。通常您使用它来将双精度数转换为整数,但它也可以反过来工作。

一些类似的 Esqueleto 函数也可能有效。

是的,这是一个 hack。希望有高手能提出更好的解决办法。

正如讨论 here there is now (since esqueleto version 2.2.9) castNum 中提到的:

castNum :: (Num a, Num b) => expr (Value a) -> expr (Value b)