Closed ocharles closed 4 years ago
At first, I thought you were describing Number
. But now I see you want to distinguish NumberOf Widget
from NumberOf Wodget
. That sounds entirely sensible to me. Is it definable outside of units
? It's been a while -- I'm not sure off the top of my head. If not, I, for one, would be willing to incorporate this idea.
The existing Number
could just become NumberOf ()
. Which, when you say it aloud ("number of unit"), makes perfect sense. :)
Aha, nice, I didn't see Number
. Yes, this should all be definable outside this library. I'll have a play and see what I can come up with. And thank you for the very prompt reply!
Ok, the only thing that I think Number
doesn't do is act as a Dimension
, which prohibits it from being composed with another dimension. So currently you can't say MkQu_DLN (Area :/ NumberOf Widget)
, for example.
Take this ghci
session. I know that two widgets take up 5m^2, and I want to calculate the area for 10 widgets.
> :set -XDataKinds
> :set -XTypeOperators
> import Data.Metrology
> import Data.Dimensions.SI (Area)
> import Data.Units.SI (Meter(Meter))
> let areaPerWidget = (5 % (Meter :* Meter)) |/| (2 % Number)
> let tenWidgets = 10 % Number
> areaPerWidget |*| tenWidgets
25.0 m^2
Ok, fine, ten widgets will require 25 m^2.
But I can also write...
> let twelveWodgets = 12 % Number
> areaPerWidget |*| twelveWodgets
30.0 m^2
But this is meaningless - it should be a type error, but there's no information in areaPerWidget
that would even allow us to create a type error:
> areaPerWidget
2.5 m^2
> :t areaPerWidget
areaPerWidget
:: Fractional n =>
Qu '[ 'F Data.Dimensions.SI.Length ('S ('S 'Zero))] 'DefaultLCSU n
The problem is Number
is dimensionless, but we do want a dimension. Really, the dimension of areaPerWidget
should be (Area :/ NumberOf Widget)
, rather than just Area
.
But it seems like the whole point of Number
is to be dimensionless, so I'm not sure about adding a dimension instance to it.
TL;DR: If we have NumberOf
it seems that it wants to be a dimension as well, but does this make sense?
You're right -- I had confused unit and dimension in my thinking. You want NumberOf
to be a dimension. (Actually, a family of dimensions.) But I think nothing stops you from doing this on your own. (That's one of the beauties of units
. It's fully customizable.) The fact that a "number of things" doesn't correspond to a dimension in physics shouldn't stop you.
This does mean that Number
, in units
, is not what you want.
Or am I missing something more important?
No, you're precisely right, I just wanted to see if this is something that actually made sense in the context of the library. I'm working with:
{-# language DataKinds #-}
{-# language PolyKinds #-}
{-# language TypeFamilies #-}
module Data.Metrology.NumberOf ( NumberOf( NumberOf ) ) where
-- units
import Data.Metrology
data NumberOf x =
NumberOf
deriving
( Show )
instance Dimension ( NumberOf x )
instance Unit ( NumberOf x ) where
type BaseUnit ( NumberOf x ) =
Canonical
type DimOfUnit ( NumberOf x ) =
NumberOf x
type instance DefaultUnitOfDim ( NumberOf x ) =
NumberOf x
and having success. Happy to contribute that back into units
if you feel it's generally useful, or we can keep it in house.
I believe others have used the same type as a dimension and as a unit, but that's not technically a supported configuration.
I'm eager to keep units
as agnostic as possible to actual units and dimensions. Perhaps contribute it to units-defs
if you like.
Glad it's working for you!
Great! I'll play around a bit more and make sure it's actually usable. If so, I may contribute it back upstream. Thanks again for the fun library!
Apologies for the somewhat sloppy issue title, it's hard to summarise this in a single sentence!
I'm using
units
to build a pricing model for some work we do at CircuitHub. Namely, I'm interested in a pricing model grounded by a sensible real-world interpretation.units
works nicely for this - I introduced a newCost
dimension (with$
unit), and now I can say things likeMkQu_DLN (Cost :/ Area)
- nice!However, a lot of our costs are actually per some specific unit. For example, parts prices expressed as unit prices. Currently, these are
MkQu_DLN Cost
, but they are really cost per something - and here my modeling is a bit stuck.I could introduce a new
PartQuantity
dimension, but this idea of a count seems to keep cropping up. It seems natural to me to have adimension, such that I can have things like
partUnitCost :: MkQu_DLN (Cost :/ NumberOf Part)
.I'm curious if this really fits in with the spirit of
units
though. In particular, it seems like a strange dimension, as it doesn't really have any units, other than an exact count of the things in question. On the other hand, it does a very good job of making sure I scale a per-unit part cost by the actual number of parts I need to order!What do the others think?