Multiplying Int and double values ​​in esqueleto?

The problem I am facing is quite simple: basically I am trying to compute the Int and Double product. In plain Haskell, I just ran

product = (fromIntegral int_val) * double_val

      

However, I cannot figure out how to do this in esqueleto. I have table B that has a "sum" column of type Int and table C which has a column "price" of type Double. When trying to fetch both and compute the product like

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

      

I am getting an error like (as expected):

Couldn't match type β€˜Double’ with β€˜Int’
Expected type: EntityField Drink Int
  Actual type: EntityField Drink Double

      

I couldn't find anything in the docs that helped me and I don't know how to do this at all. (See full example below for details).

Possible solution: I could of course just store the price as Int, but I'm wondering if this can be done using esqueleto.

Complete example :

Database:

Table A: Id | Name

Table B: Id | AId | BId | Sum where Amount is Int, and AId and BId are references to tables A and B.

Table C: Id | Name | Price, here Price Double

The request I recorded looks like this:

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)

      

EDIT

I've tried using fmap

and fromIntegral

like this:

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

      

which results in two errors: No instance for (Functor SqlExpr)

and No instance for (Num (Value Double))

As suggested in the comments (by @Thomas M. DuBuisson) I tried:

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

      

which solves the second problem, but I still get it No instance for (Functor SqlExpr)

.

EDIT 2 :

I asked about this on the Yesod mailing list. A discussion can be found here .

+3


source to share


2 answers


As mentioned in the discussion here now (since esqueleto version 2.2.9) castNum for this purpose:



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

      

0


source


I'm not an expert, but you can try applying integer_floor

to your parameter :

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

      

It can turn your whole in double, as a

and b

may be different. You usually use it to convert doubles to integers, but it can also work the other way around.



Some of Esqueleto's similar features may work as well.

And yes, it's a hack. Hope some expert can suggest a better solution.

+1


source







All Articles