iliekturtles / uom

Units of measurement -- type-safe zero-cost dimensional analysis

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Functor / map

jacg opened this issue · comments

Some related pain points of using uom include

  • methods defined on floats and ints lag behind std
  • cannot use functions defined on floats and ints
  • defining functions generic over quantities is, in any practical sense, impossible.

If this were Haskell, Quantity would be an applicative functor and it would be trivial to perform any operation that is defined on the internal storage type, 'inside' the Quantity: all the above would be non-problems. This isn't Haskell, and Rust doesn't have an abstraction for functors, let alone applicative ones, but Rust does implement the functor pattern over and over again pretty much everywhere with ad-hoc implementations of .map(...) ... because it's too useful a pattern to be ignored.

Is there any reason why Quantity could/should not be turned into an ad-hoc functor by implementing .map(...)?

That would solve the problem of single input functions in one fell swoop. More than one input would require something like applicative functors, and a feasible Rusty solution might simply be to provide a number of ad-hoc n-argument methods such as .apply{2..N}(...) or .map{2..N}(...).

If this were Haskell, Quantity would be an applicative functor and it would be trivial to perform any operation that is defined on the internal storage type, 'inside' the Quantity: all the above would be non-problems.

I don't think this is correct as the type system has no information how any given operation "interacts" with the exponents defining the quanitity, e.g. that addition produces the same quantity whereas multiplication changes it is exactly the kind of domain knowledge that uom encodes in its type signatures.

Is there any reason why Quantity could/should not be turned into an ad-hoc functor by implementing .map(...)?

Due to the above, a generic map would be somewhat unsafe (in the domain sense, not in Rust's memory safety sense) as it would be necessary to have an unconstrained return type and the user would have to make sure to properly guide type inference to match the operation passed to map. I suspect that this would end up basically as brittle as defining generic function is cumbersome now. Furthermore, it would spread out the problem to the usage sites instead of a single definition site.

Yes: it could only work for the quantity-preserving operations, and for some reason I had tunnel vision restricting my thoughts to those cases.

Apologies for the noise.