add implicitly chain for angle conversion factors#52
add implicitly chain for angle conversion factors#52ldrygala wants to merge 5 commits intoto-ithaca:masterfrom
Conversation
Codecov Report
@@ Coverage Diff @@
## master #52 +/- ##
==========================================
- Coverage 85.82% 85.24% -0.59%
==========================================
Files 10 10
Lines 254 244 -10
==========================================
- Hits 218 208 -10
Misses 36 36
Continue to review full report at Codecov.
|
src/main/scala/libra/ops/base.scala
Outdated
| } | ||
|
|
||
| object ConversionFactor { | ||
| implicit def inductiveAngelConversionFactor[A, From <: UnitOfMeasure[Angle], To <: UnitOfMeasure[Angle], Next <: UnitOfMeasure[Angle]]( |
There was a problem hiding this comment.
Could this part be generic on any dimension D instead of Angle?
There was a problem hiding this comment.
i tried but i didn't work (diverging implicit expansion for type libra.ops.base.ConversionFactor), therefor i used Angle. I will try one more time to make it more generic
There was a problem hiding this comment.
That's ok, there's no need if you already tried! I'll take a better look at it later this week. I've debugged a fair few implicit resolution errors by now, so may have more luck.
There was a problem hiding this comment.
Ok, so i'm waiting for your solution and i hope that i'll be able to understand them :)
| implicit def inductiveAngelConversionFactor[A, From <: UnitOfMeasure[Angle], To <: UnitOfMeasure[Angle], Next <: UnitOfMeasure[Angle]]( | ||
| implicit multiplicativeSemigroup: MultiplicativeSemigroup[A], | ||
| fromConversion: ConversionFactor[A, Angle, From, Next], | ||
| toConversion: Lazy[ConversionFactor[A, Angle, Next, To]] |
src/main/scala/libra/ops/base.scala
Outdated
| } | ||
|
|
||
| object ConversionFactor { | ||
| implicit def inductiveAngelConversionFactor[A, From <: UnitOfMeasure[Angle], To <: UnitOfMeasure[Angle], Next <: UnitOfMeasure[Angle]]( |
|
Thanks @ldrygala this looks awesome! It removes the otherwise exponential boilerplate. Sorry for not getting round to this earlier - I had a nasty cold and couldn't code for a few days. Would it be possible to make it even more generic in dimension? |
|
@zainab-ali i removed unused compose function on |
|
@ldrygala I'd like to sort out the implicit resolution issues for the general case. I don't think we're too far off a solution for this. I've been investigating why there are implicit resolution issues with general dimensions, other than What we have is a graph of potential conversions, and we'd like the compiler to pick out a specific path. However, even if the derivation works, the approach isn't ideal. This is mainly because:
@milessabin suggested the interesting alternative of providing evidence in the form of a // This can only be created with appropriate conversions from each node
implicit val conversionPath : ConversionPath[Degree :: ArcMinute :: ArcSecond :: HNil] = mkConversionPath
Deriving conversion factors would then be a matter of finding two nodes in the path and traversing all the nodes in between. This would pose a problem in cases where we wanted to define different units for the same base dimensions in different packages. implicit val conversionPathMetric : ConversionPath[Second :: Millisecond :: _ :: HNil] = mkConversionPath
implicit val conversionPathDay : ConversionPath[Second :: Hour :: Day :: HNil] = mkConversionPathAnd then somehow relate the two using a lower priority implicit. This would be a bit more effort, but would provide better messages in the long run. I'll experiment with this over the next few days, and see if I can come to a solution on it. |
|
@zainab-ali very interesting idea with conversionPath represented as HList. Is there anything I can get involved with this PR ? |
|
Would you like to have a go at it? It involves some fairly heavy induction, which is not everyone's cup of tea, believe me. The steps I'm envisaging are as follows:
Creating the path is fairly straightforward: package libra
package ops
import base.ConversionFactor
import shapeless._
import shapeless.ops.hlist._
trait ConversionPath[A, D, H <: HList] {
type Out <: HList
val path: Out
}
object ConversionPath {
type Aux[A, D, H <: HList, Out0 <: HList] = ConversionPath[A, D, H] { type Out = Out0 }
implicit def conversionPathBase[A, D, F <: UnitOfMeasure[D], T <: UnitOfMeasure[D]](
implicit ev: ConversionFactor[A, D, F, T]
): ConversionPath.Aux[A, D, F :: T :: HNil, ConversionFactor[A, D, F, T] :: HNil] =
new ConversionPath[A, D, F :: T :: HNil] {
type Out = ConversionFactor[A, D, F, T] :: HNil
val path = ev :: HNil
}
implicit def conversionPathRecurse[A, D, F <: UnitOfMeasure[D], T <: UnitOfMeasure[D],
Tail <: HList, OutTail <: HList](
implicit ev: ConversionPath.Aux[A, D, T :: Tail, OutTail],
ev1: ConversionFactor[A, D, F, T]
): ConversionPath.Aux[A, D, F :: T :: Tail, ConversionFactor[A, D, F, T] :: OutTail] =
new ConversionPath[A, D, F :: T :: Tail] {
type Out = ConversionFactor[A, D, F, T] :: OutTail
val path = ev1 :: ev.path
}
}
Step 2 is more challenging. Let me know if you'd like to give it a try. |
|
i thought that maybe there will be some easy thing to do, but it looks very hard, so therefore i can only wish you good luck. |
|
I've finally finished the package refactor! I'll be able to work on this over the weekend. |
add inductive implicit for chaining angle conversion factors, as referenced in #50