在 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)
编辑:
我试过像这样使用 fmap
和 fromIntegral
:
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)
这可能会将您的整数转换为双精度整数,因为 a
和 b
可能不同。通常您使用它来将双精度数转换为整数,但它也可以反过来工作。
一些类似的 Esqueleto 函数也可能有效。
是的,这是一个 hack。希望有高手能提出更好的解决办法。
正如讨论 here there is now (since esqueleto version 2.2.9) castNum 中提到的:
castNum :: (Num a, Num b) => expr (Value a) -> expr (Value b)
我面临的问题非常简单:基本上我正在尝试计算 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)
编辑:
我试过像这样使用 fmap
和 fromIntegral
:
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)
这可能会将您的整数转换为双精度整数,因为 a
和 b
可能不同。通常您使用它来将双精度数转换为整数,但它也可以反过来工作。
一些类似的 Esqueleto 函数也可能有效。
是的,这是一个 hack。希望有高手能提出更好的解决办法。
正如讨论 here there is now (since esqueleto version 2.2.9) castNum 中提到的:
castNum :: (Num a, Num b) => expr (Value a) -> expr (Value b)