goldfirere / units

The home of the units Haskell package
94 stars 19 forks source link

Making Quantities from UnitExp #65

Closed Montmorency closed 2 years ago

Montmorency commented 3 years ago

Firstly, many thanks for making this library available!

I'm having a bit of a conceptual issue/question that I haven't been able to resolve. I've managed to use this module quite successfully where I have all my quantities/units/dimensions and combinations thereof specified at compile time.

I am now trying to put together a little demonstration application which would accept Unit strings at runtime from a user and, provided the strings are parsed succesfully, perform conversions between them.

On a successful parse of an input string I have some data UnitExp pre unit. But I am not sure how to proceed from there. For instance a test function to try and make a quantity (say I have parsed "m/s" and lifted UnitExp out of the Either monad):

liftUnitExp :: (Show unit) => (UnitExp pre unit) -> Double -> IO ()  --Qu dim lcsu n
liftUnitExp (UnitExp pre unit) x = print (x % unit) 

Gives me a compilation error:

    • Could not deduce (UnitFactor
                          (LookupList (DimFactorsOf (DimOfUnit unit)) 'DefaultLCSU))
        arising from a use of ‘%’

This seems to be because I'm unsure of what the proper way of associating an appropriate LCSU is with my parsed UnitExp Data. Essentially the problem seems to be that I can't see a way of making a "runtime-type equivalent" to MkQu_ULN Unit LCSU Double, something like MkQuRunTime_ULN UnitExp LCSU Double.

So I suppose the question is: am I trying to do something too far counter to what the units/units-parser is designed for? Or is there some pattern I can apply so that I can get past the type checker and have the UnitExp -> Quantity evaluated at runtime.

Cheers.

goldfirere commented 3 years ago

What you ask for is immanently sensible. After all, units knows how to do everything you want at compile-time. Runtime happens after compile-time, so why can't it just delay the computation? Well, it can't. :) Part of the problem is that the instance-lookup mechanism only exists during compilation, and that instance-lookup mechanism is a key part to figuring out the conversions.

So, short of, say, generating a temporary .hs file and invoking ghc from your application, I don't think units can solve your problem.

On the other hand, units-defs has all the information you need to do the conversions, and you may be able to adapt that information and build an application (without using units directly) that uses this information to do what you want.

I hope this is helpful!

Montmorency commented 3 years ago

Woops accidentally hit close comment there. Thanks for reply the run time/compile time argument was what made me think it could be just about possible but I had a feeling there was something a little more subtle going on that I was missing. The calling ghc route sounds tempting but maybe a bit too spicy... I'll go with a pure units-def solution for now and post link. Thanks again!

goldfirere commented 2 years ago

It looks like there is nothing further to do here -- to get runtime conversions as you seek would require a whole new dimension (ha ha) to this package. If someone wants to contribute a design, code, and maintenance time, I would be happy to have such a feature here, but I do not plan on implementing it myself.