Skip to content

Remove Quantity typeclass instance of QDefinition.#4140

Open
balacij wants to merge 6 commits intomainfrom
rmQuantityInstanceOfQDefinition
Open

Remove Quantity typeclass instance of QDefinition.#4140
balacij wants to merge 6 commits intomainfrom
rmQuantityInstanceOfQDefinition

Conversation

@balacij
Copy link
Collaborator

@balacij balacij commented Jun 6, 2025

Contributes to #4097

A QDefinition is not a Quantity. A QDefinition only pairs a 'quantity' with a 'defining formula'.

@JacquesCarette
Copy link
Owner

So what do you think a Quantity is? I agree that a QDefinition pairs a 'quantity' with a 'defining formula'. The real question: is the 'defining formula' a mere annotation, thus making a QDefinition a Quantity, or something entirely different, thus changing the very nature of QDefinition?

@balacij balacij marked this pull request as ready for review June 7, 2025 18:55
@balacij
Copy link
Collaborator Author

balacij commented Jun 7, 2025

I finished the work, and I've also marked the PR as "ready for review" so that the CI can run. However, the PR is not quite "ready to merge" because your comment has me second-guessing.

I see your point, and I subscribe to your view on what a 'Quantity' is.

Brain dump: I think of 'QDefinition's as specific solutions to calculating a quantity. i.e., its nature is about calculation, not about defining a symbol. If a 'QDefinition' were a 'Quantity', then could we say that a 'QDefinition' is equal to a 'UnitalChunk' about them being 'Quantities'? Would that relate to them having the same symbol, UID, space, formula (the 'UnitalChunk' doesn't have a formula)?

If a 'QDefinition' provides an approximate solution to a QuantityDict, does it change the definition of the QuantityDict? Of course, I'm not talking about mutation here, but about a cloned QuantityDict that explicitly mentions it is approximated, potentially with a slightly different symbol.

I think we can also look at the "names" (I'll refrain from saying "terms" here) of these things. Wouldn't we want the names of the QuantityDict to be different from the QDefinition? We currently have this in Drasil with our IMs showing "Calculation of $x$" -- that is information embedded in the QDefinition, arguably hacked in through its internal DefinedQuantityDict and sometimes overridden by the carrier EquationalModel. For example, Projectile has:

timeIM :: InstanceModel
timeIM = imNoRefs (equationalModelN (nounPhraseSP "calculation of landing time") timeQD)
  [qwC launSpeed $ UpFrom (Exc, exactDbl 0)
  ,qwC launAngle $ Bounded (Exc, exactDbl 0) (Exc, half $ sy pi_)]
  (qw flightDur) [UpFrom (Exc, exactDbl 0)]
  (Just timeDeriv) "calOfLandingTime" [angleConstraintNote, gravitationalAccelConstNote, timeConsNote]

Overall, I still tend towards a 'QDefinition' not being a 'Quantity', but I'm not entirely convinced anymore. What do you think?

UT.heatTransferCoef Real
[gtZeroConstr,
sfwrRange $ Bounded (Inc, sy coilHTCMin) (Inc, sy coilHTCMax)] (exactDbl 1000) defaultUncrt
sfwrRange $ Bounded (Inc, sy $ coilHTCMin ^. defLhs) (Inc, sy $ coilHTCMax ^. defLhs)] (exactDbl 1000) defaultUncrt
Copy link
Collaborator Author

@balacij balacij Jun 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like that that ^. defLhs is appearing here. But I'm confused now: Should this quantity definition declaration be dependant on QDefinitions?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, it shouldn't. coilHTCMin is a QDefinition that deeply nests a QuantityDict within it, which isn't accessible elsewhere. I think we need to de-nest these things. Before I start that, @JacquesCarette, do you agree?

coilHTCMin = mkQuantDef (unitary' "coilHTCMin"
  (nounPhraseSP $ "minimum convective heat " ++
  "transfer coefficient between coil and water")
  (staged (supMin (eqSymb coilHTC)) (subMin (eqSymb coilHTC))) 
  UT.heatTransferCoef Real) $ exactDbl 10

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That all the information from a QuantityDict is available from a QDefinition seems quite reasonable to me. How that is encoded, that is a different question. So it depends on what we mean by a QDefinition, i.e. what is it meant to represent.

@JacquesCarette
Copy link
Owner

I think of 'QDefinition's as specific solutions to calculating a quantity. i.e., its nature is about calculation, not about defining a symbol.

That a priori makes sense. Though I think that's what DataDefinitions are for. I think the case of QDefinition was when you are creating a new symbol, but you are also associating a way to compute it at the same time.

How many QDefinitions do we have? I think we need to look at all of them, to see what knowledge we're trying to capture with them. That's really going to be where the proper design has to stem from.

[I have no idea why you're talking about 'approximation' above.]

Overall, I still tend towards a 'QDefinition' not being a 'Quantity', but I'm not entirely convinced anymore.

Whereas I suspect that the real problem is that we are not capturing the information that we need "the right way".

Copy link
Owner

@JacquesCarette JacquesCarette left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this PR has some good things, and some dubious things.

I think part of the issue is that we don't know what the Quantity constraint means. Does it mean "is a quantity"? Or does it mean "represents a quantity"? Nor do we really know what QDefinition is supposed to embody. So it is really hard to know of those instances should be there or not.

qtoc :: (Quantity (q Expr), MayHaveUnit (q Expr), DefiningExpr q) => q Expr -> CodeDefinition
qtoc q = CD (codeChunk $ quantfunc q) (expr $ q ^. defnExpr) [] Definition

qtoc' :: QDefinition Expr -> CodeDefinition
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't like this signature. The previous one was nicely polymorphic, this one is monomorphic. That's a regression.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, qtoc' was a bit unnecessary. Fixed in b1dca9e

cnsts)
derived = map qtov $ getDerivedInputs ddefs inputs' const' db
rels = (map qtoc (getEqModQdsFromIm ims ++ mapMaybe qdEFromDD ddefs) \\ derived)
rels = (map qtoc' (getEqModQdsFromIm ims ++ mapMaybe qdEFromDD ddefs) \\ derived)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is kind of good - not the qtoc' call per se, but the fact that the information is actually coming from IMs and DDs. What's wrong is how the code is extracting the information. This seems to indicate we have the 'wrong' lenses for that purpose.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice to remove getEqModQdsFromIm and qdEFromDD. We could expose a type parameter that indicates what kind of model the IM is (e.g., InstanceModel Definitional), this way we could have a lens that operates on X Definitionals to get their QDefinitions.

Alternatively, we can really redesign what's going on here. It might be nice to see a 'system of equations' chunk that we gradually build by creating IMs.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice to remove getEqModQdsFromIm and qdEFromDD

Why? I agree they shouldn't return chunks, but otherwise, this seems like a good way to extract information.

Yes, it would be "icing on the cake" if we could use Haskell's type system to prevent us from grabbing the wrong thing. But that's an optimization.

@balacij
Copy link
Collaborator Author

balacij commented Jul 9, 2025

How many QDefinitions do we have? I think we need to look at all of them, to see what knowledge we're trying to capture with them. That's really going to be where the proper design has to stem from.

Using rg "^[^\-].+fromEqn|mkQuantDef| ec " -ths --sort-files --stats to estimate, we have around 180:

189 matches
184 matched lines
34 files contained matches
469 files searched
13492 bytes printed
2798685 bytes searched
0.002789 seconds spent searching
0.037277 seconds
All matches (hidden).
drasil-data/lib/Data/Drasil/Equations/Defining/Physics.hs
29:accelerationQD = mkQuantDef QP.acceleration accelerationEqn
32:velocityQD = mkQuantDef QP.velocity velocityEqn
35:newtonSLQD = fromEqn' "force" (nounPhraseSP "Newton's second law of motion")

drasil-data/lib/Data/Drasil/Quantities/Math.hs
42:piConst = mkQuantDef pi_ (dbl 3.14159265)

drasil-data/lib/Data/Drasil/Quantities/Physics.hs
145:gravitationalConstValue = mkQuantDef gravitationalConst (dbl 6.6743E-11)
149:gravitationalAccelConst = mkQuantDef gravitationalMagnitude (dbl 9.8)

drasil-data/lib/Data/Drasil/Theories/Physics.hs
39:weightQD = mkQuantDef' QP.weight (nounPhraseSP "weight") weightEqn
83:hsPressureQD = mkQuantDef' QP.pressure (nounPhraseSP "hydrostatic pressure") hsPressureEqn
100:torque = mkQuantDef QP.torque torqueEqn
113:vecMagQD = mkQuantDef QP.speed speedEqn
131:newtonSLRQD = mkQuantDef' QP.torque (nounPhraseSP "Newton's second law for rotational motion") newtonSLRExpr

drasil-example/dblpend/lib/Drasil/DblPend/DataDefs.hs
25:positionGQD = mkQuantDef velocity positionGEqn
37:positionXQD_1 = mkQuantDef xPos_1 positionXEqn_1
55:positionYQD_1 = mkQuantDef yPos_1 positionYEqn_1
73:positionXQD_2 = mkQuantDef xPos_2 positionXEqn_2
91:positionYQD_2 = mkQuantDef yPos_2 positionYEqn_2
109:accelGQD = mkQuantDef acceleration accelGEqn
121:forceGQD = mkQuantDef force forceGEqn

drasil-example/dblpend/lib/Drasil/DblPend/GenDefs.hs
38:velXQD_1 = mkQuantDef' xVel_1 (the xComp `NP.of_` (velocity `ofThe` firstObject)) E.velXExpr_1
67:velYQD_1 = mkQuantDef' yVel_1 (the yComp `NP.of_` (velocity `ofThe` firstObject)) E.velYExpr_1
88:velXQD_2 = mkQuantDef' xVel_2 (the xComp `NP.of_` (velocity `ofThe` secondObject)) E.velXExpr_2
109:velYQD_2 = mkQuantDef' yVel_2 (the yComp `NP.of_` (velocity `ofThe` secondObject)) E.velYExpr_2
130:accelXQD_1 = mkQuantDef' xAccel_1 (the xComp `NP.of_` (acceleration `ofThe` firstObject)) E.accelXExpr_1
156:accelYQD_1 = mkQuantDef' yAccel_1 (the yComp `NP.of_` (acceleration `ofThe` firstObject)) E.accelYExpr_1
177:accelXQD_2 = mkQuantDef' xAccel_2 (the xComp `NP.of_` (acceleration `ofThe` secondObject)) E.accelXExpr_2
198:accelYQD_2 = mkQuantDef' yAccel_2 (the yComp `NP.of_` (acceleration `ofThe` secondObject)) E.accelYExpr_2

drasil-example/gamephysics/lib/Drasil/GamePhysics/DataDefs.hs
42:ctrOfMass = mkQuantDef posCM ctrOfMassEqn
70:linDisp = mkQuantDef QP.linearDisplacement dispEqn
99:linVel = mkQuantDef QP.linearVelocity velEqn
117:linAcc = mkQuantDef QP.linearAccel accelEqn
135:angDisp = mkQuantDef QP.angularDisplacement angDispEqn
153:angVel = mkQuantDef QP.angularVelocity angVelEqn
171:angAccel = mkQuantDef QP.angularAccel angAccelEqn
198:chasles = mkQuantDef' velB (nounPhraseSP "Chasles' theorem") chaslesEqn
218:impulseV = mkQuantDef QP.impulseV impulseVEqn
249:reVelInColl = mkQuantDef initRelVel reVelInCollEqn
269:coeffRestitution = mkQuantDef QP.restitutionCoef coeffRestitutionEqn
289:kEnergy = mkQuantDef QP.kEnergy kEnergyEqn
303:momentOfInertia = mkQuantDef QP.momentOfInertia momentOfInertiaEqn
320:potEnergy = mkQuantDef QP.potEnergy potEnergyEqn

drasil-example/gamephysics/lib/Drasil/GamePhysics/GenDefs.hs
70:accelGravityQD = mkQuantDef' QP.gravitationalAccel (nounPhraseSP "Acceleration due to gravity") accelGravityExpr
150:impulseQD = mkQuantDef' QP.impulseS (nounPhraseSP "Impulse for Collision") impulseExpr

drasil-example/gamephysics/lib/Drasil/GamePhysics/IMods.hs
48:transMotQD = mkQuantDef accj transMotExpr
94:rotMotQD = mkQuantDef angAccj rotMotExpr

drasil-example/gamephysics/lib/Drasil/GamePhysics/TMods.hs
35:newtonTLQD = mkQuantDef' force_1 (nounPhraseSP "Newton's third law of motion") newtonTLExpr
86:newtonSLRQD = mkQuantDef' torque (nounPhraseSP "Newton's second law for rotational motion") newtonSLRExpr

drasil-example/glassbr/lib/Drasil/GlassBR/DataDefs.hs
37:hFromtQD = mkQuantDef minThick hFromtEq
48:loadDFQD = mkQuantDef lDurFac loadDFEq
63:glaTyFacQD = mkQuantDef gTF glaTyFacEq
75:standOffDisQD = mkQuantDef standOffDist standOffDisEq
86:aspRatQD = mkQuantDef aspectRatio aspRatEq
97:eqTNTWQD = mkQuantDef eqTNTWeight eqTNTWEq
108:calofDemandQD = mkQuantDef demand calofDemandEq

drasil-example/glassbr/lib/Drasil/GlassBR/IMods.hs
53:riskQD = mkQuantDef riskFun ((sy sflawParamK $/
67:strDisFacQD = mkQuantDef stressDistFac strDisFacEq
87:nonFLQD = mkQuantDef nonFactorL nonFLEq
102:dimLLQD = mkQuantDef dimlessLoad dimLLEq
117:tolPreQD = mkQuantDef tolLoad tolPreEq
129:tolStrDisFacQD = mkQuantDef sdfTol $ ln (ln (recip_ (exactDbl 1 $- sy pbTol))
142:probOfBreakQD = mkQuantDef probBr (exactDbl 1 $- exp (neg $ sy $ risk ^. output))
152:calofCapacityQD = mkQuantDef lRe (sy (nonFL ^. output) $* sy (glaTyFac ^. defLhs) $* sy loadSF)
162:pbIsSafeQD = mkQuantDef isSafePb (sy probBr $< sy pbTol)
174:lrIsSafeQD = mkQuantDef isSafeLR (sy lRe $> sy demand)

drasil-example/glassbr/lib/Drasil/GlassBR/TMods.hs
30:lrIsSafeQD = mkQuantDef' isSafeLoad (nounPhraseSP "Safety Load") lrIsSafeExpr
45:pbIsSafeQD = mkQuantDef' isSafeProb (nounPhraseSP "Safety Probability") pbIsSafeExpr

drasil-example/glassbr/lib/Drasil/GlassBR/Unitals.hs
160:dimMax     = mkQuantDef (unitary "dimMax"
164:dimMin     = mkQuantDef (unitary "dimMin"
168:arMax     = mkQuantDef (vc "arMax"
172:cWeightMax = mkQuantDef (unitary "cWeightMax"
176:cWeightMin = mkQuantDef (unitary "cWeightMin"
180:sdMax     = mkQuantDef (unitary "sdMax"
184:sdMin     = mkQuantDef (unitary "sdMin"
188:stressDistFacMin = mkQuantDef (vc "stressDistFacMin" (nounPhraseSP "minimum value for the stress distribution factor")
191:stressDistFacMax = mkQuantDef (vc "stressDistFacMax" (nounPhraseSP "maximum value for the stress distribution factor")
408:constantK       = mkQuantDef sflawParamK $ dbl 2.86e-53
409:constantM       = mkQuantDef sflawParamM $ exactDbl 7
410:constantModElas = mkQuantDef modElas     $ dbl 7.17e10
411:constantLoadDur = mkQuantDef loadDur     $ exactDbl 3
412:constantLoadSF  = mkQuantDef loadSF      $ exactDbl 1

drasil-example/hghc/lib/Drasil/HGHC/HeatTransfer.hs
47:htTransCladCool = fromEqn "htTransCladCool" (nounPhraseSP
61:htTransCladFuel = fromEqn "htTransCladFuel" (nounPhraseSP

drasil-example/pdcontroller/lib/Drasil/PDController/DataDefs.hs
26:ddErrSigDefn = mkQuantDef qdProcessErrorFD ddErrSigEqn
51:ddPropCtrlDefn = mkQuantDef qdPropControlFD ddPropCtrlEqn
72:ddDerivCtrlDefn = mkQuantDef qdDerivativeControlFD ddDerivCtrlEqn
95:ddCtrlVarDefn = mkQuantDef qdCtrlVarFD ddCtrlEqn

drasil-example/pdcontroller/lib/Drasil/PDController/Unitals.hs
118:odeAbsTolConst = mkQuantDef dqdAbsTol (dbl 1.0e-10)
119:odeRelTolConst = mkQuantDef dqdRelTol (dbl 1.0e-10)

drasil-example/projectile/lib/Drasil/Projectile/DataDefs.hs
24:speedIXQD = mkQuantDef ixVel $ sy iSpeed $* cos (sy launAngle)
25:speedIYQD = mkQuantDef iyVel $ sy iSpeed $* sin (sy launAngle)

drasil-example/projectile/lib/Drasil/Projectile/GenDefs.hs
37:rectVelQD = mkQuantDef' projSpeed (nounPhraseSent $ foldlSent_ 
61:rectPosQD = mkQuantDef' projPos (nounPhraseSent $ foldlSent_ 
85:velVecQD = mkQuantDef' velocity (nounPhraseSent $ foldlSent_ 
102:posVecQD = mkQuantDef' position (nounPhraseSent $ foldlSent_ 

drasil-example/projectile/lib/Drasil/Projectile/IMods.hs
44:timeQD = mkQuantDef flightDur E.flightDur'
83:landPosQD = mkQuantDef landPos E.landPosExpr
116:offsetQD = mkQuantDef offset E.offset'
126:messageQD = mkQuantDef message E.message

drasil-example/projectile/lib/Drasil/Projectile/Unitals.hs
47:tol = mkQuantDef (vcSt "tol" (nounPhraseSP "hit tolerance") (autoStage vEpsilon) Real) (perc 2 2)

drasil-example/sglpend/lib/Drasil/SglPend/DataDefs.hs
27:positionIXQD = mkQuantDef QP.ixPos positionIXEqn
43:positionIYQD = mkQuantDef QP.iyPos positionIYEqn
60:frequencyDDQD = mkQuantDef QP.frequency frequencyDDEqn
75:angFrequencyDDQD = mkQuantDef QP.angularFrequency angFrequencyDDEqn
89:periodSHMDDQD = mkQuantDef QP.period periodSHMDDEqn

drasil-example/sglpend/lib/Drasil/SglPend/GenDefs.hs
45:velocityIXQD = mkQuantDef' xVel (the xComp `NP.of_` (velocity `ofThe` pendulum))
72:velocityIYQD = mkQuantDef' yVel (the yComp `NP.of_` (velocity `ofThe` pendulum)) $ express E.velocityIYExpr
93:accelerationIXQD = mkQuantDef' xAccel (the xComp `NP.of_` (acceleration `ofThe` pendulum))
122:accelerationIYQD = mkQuantDef' yAccel (the yComp `NP.of_` (acceleration `ofThe` pendulum)) $ express E.accelerationIYExpr
183:angFrequencyQD = mkQuantDef' angularFrequency (angularFrequency `the_ofThe` pendulum) $ express E.angFrequencyExpr
219:periodPendQD = mkQuantDef' period (NP.the (period `ofThe` pendulum)) $ express E.periodPendExpr

drasil-example/ssp/lib/Drasil/SSP/DataDefs.hs
42:intersliceWtrFQD = mkQuantDef watrForce intersliceWtrFEqn
65:angleAQD = mkQuantDef baseAngle angleAEqn
84:angleBQD = mkQuantDef surfAngle angleBEqn
102:lengthBQD = mkQuantDef baseWthX lengthBEqn
115:lengthLbQD = mkQuantDef baseLngth lengthLbEqn
132:lengthLsQD = mkQuantDef surfLngth lengthLsEqn
149:slcHeightQD = mkQuantDef midpntHght slcHeightEqn
168:normStressQD = mkQuantDef totNormStress normStressEqn
179:tangStressQD = mkQuantDef tangStress tangStressEqn
191:ratioVarQD = mkQuantDef scalFunc ratioVarEqn
207:convertFunc1QD = mkQuantDef shrResC convertFunc1Eqn
225:convertFunc2QD = mkQuantDef mobShrC convertFunc2Eqn
247:resShearWOQD = mkQuantDef shearRNoIntsl resShearWOEqn
269:mobShearWOQD = mkQuantDef shearFNoIntsl mobShearWOEqn
297:nrmForceSumQD = ec nrmForceSum (inxi intNormForce $+ inxiM1 intNormForce)
300:watForceSumQD = ec watForceSum (inxi watrForce $+ inxiM1 watrForce)
303:sliceHghtRightQD = ec sliceHghtRight (inxi slopeHght $- inxi slipHght)
306:sliceHghtLeftQD = ec sliceHghtLeft (inxiM1 slopeHght $- inxiM1 slipHght)

drasil-example/ssp/lib/Drasil/SSP/GenDefs.hs
194:normShrR = mkQuantDef intShrForce nmShrRExpr

drasil-example/ssp/lib/Drasil/SSP/IMods.hs
61:fctSftyQD = mkQuantDef' fs factorOfSafety fctSftyExpr
385:nrmShrForQD = mkQuantDef normToShear nrmShrFExpr
611:crtSlpIdQD = mkQuantDef fsMin crtSlpIdExpr

drasil-example/ssp/lib/Drasil/SSP/TMods.hs
42:factOfSafetyQD = mkQuantDef' fs factorOfSafety factOfSafetyExpr
84:mcShrStrgthQD = fromEqnSt' (shrStress ^. uid) (nounPhraseSP "Mohr-Coulumb shear strength")
114:effStressQD = fromEqnSt' (effectiveStress ^. uid) (nounPhraseSP "effective stress")

drasil-example/swhs/lib/Drasil/SWHS/DataDefs.hs
40:waterMassQD = mkQuantDef wMass waterMassEqn
54:waterVolumeQD = mkQuantDef wVol waterVolumeEqn
70:tankVolumeQD = mkQuantDef tankVol tankVolumeEqn
81:balanceDecayRateQD = mkQuantDef tauW balanceDecayRateEqn
97:balanceDecayTimeQD = mkQuantDef eta balanceDecayTimeEqn
109:balanceSolidPCMQD = mkQuantDef tauSP balanceSolidPCMEqn
122:balanceLiquidPCMQD = mkQuantDef tauLP balanceLiquidPCMEqn
135:ddHtFusionQD = mkQuantDef htFusion htFusionEqn
154:ddMeltFracQD = mkQuantDef meltFrac meltFracEqn
172:aspRatQD = mkQuantDef aspectRatio aspRatEq

drasil-example/swhs/lib/Drasil/SWHS/GenDefs.hs
61:htFluxWaterFromCoilQD = mkQuantDef htFluxC htFluxWaterFromCoilExpr
75:htFluxPCMFromWaterQD = mkQuantDef htFluxP htFluxPCMFromWaterExpr

drasil-example/swhs/lib/Drasil/SWHS/TMods.hs
84:sensHtEQD pc eqn desc = fromEqnSt'' "sensHeat" np desc (symbol sensHeat) (sensHeat ^. typ) eqn

drasil-example/swhs/lib/Drasil/SWHS/Unitals.hs
474:consTolAux = mkQuantDef consTol $ perc 1 5
477:tankLengthMin = mkQuantDef (unitary "tankLengthMin"
481:tankLengthMax = mkQuantDef (unitary "tankLengthMax"
485:fracMinAux = mkQuantDef fracMin $ dbl 1.0e-6
487:arMin = mkQuantDef aspectRatioMin $ dbl 0.01
488:arMax = mkQuantDef aspectRatioMax $ exactDbl 100
491:pcmDensityMin = mkQuantDef (unitary' "pcmDensityMin"
495:pcmDensityMax = mkQuantDef (unitary' "pcmDensityMax"
500:htCapSPMin = mkQuantDef (unitary "htCapSPMin"
504:htCapSPMax = mkQuantDef (unitary "htCapSPMax"
509:htCapLPMin = mkQuantDef (unitary "htCapLPMin"
513:htCapLPMax = mkQuantDef (unitary "htCapLPMax"
518:htFusionMin = mkQuantDef (unitary "htFusionMin"
522:htFusionMax = mkQuantDef (unitary "htFusionMax"
527:coilSAMax = mkQuantDef (unitary' "coilSAMax"
532:wDensityMin = mkQuantDef (unitary' "wDensityMin"
536:wDensityMax = mkQuantDef (unitary' "wDensityMax"
541:htCapWMin = mkQuantDef (unitary' "htCapWMin"
546:htCapWMax = mkQuantDef (unitary' "htCapWMax"
552:coilHTCMin = mkQuantDef (unitary' "coilHTCMin"
558:coilHTCMax = mkQuantDef (unitary' "coilHTCMax"
565:pcmHTCMin = mkQuantDef (unitary' "pcmHTCMin"
571:pcmHTCMax = mkQuantDef (unitary' "pcmHTCMax"
578:timeFinalMax = mkQuantDef (unitary' "timeFinalMax"

drasil-example/swhsnopcm/lib/Drasil/SWHSNoPCM/DataDefs.hs
18:waterVolumeQD = mkQuantDef wVol waterVolumeEqn

drasil-lang/lib/Language/Drasil/Chunk/Eq.hs
10:  fromEqn, fromEqn', fromEqnSt,
11:  fromEqnSt', fromEqnSt'', mkQDefSt, mkQuantDef, mkQuantDef', ec,
109:mkQDefSt u n s symb sp (Just ud) e = fromEqnSt u n s symb sp ud e
110:mkQDefSt u n s symb sp Nothing   e = fromEqnSt' u n s symb sp e
113:mkQuantDef :: (Quantity c, MayHaveUnit c) => c -> e -> QDefinition e
114:mkQuantDef c = mkQDefSt (c ^. uid) (c ^. term) EmptyS (symbol c) (c ^. typ) (getUnit c)
118:mkQuantDef' :: (Quantity c, MayHaveUnit c) => c -> NP -> e -> QDefinition e
119:mkQuantDef' c t = mkQDefSt (c ^. uid) t EmptyS (symbol c) (c ^. typ) (getUnit c)

drasil-lang/lib/Language/Drasil.hs
111:  , QDefinition, fromEqn, fromEqn', fromEqnSt, fromEqnSt', fromEqnSt''
112:  , mkQDefSt, mkQuantDef, mkQuantDef', ec
358:import Language.Drasil.Chunk.Eq (QDefinition, fromEqn, fromEqn', fromEqnSt,
359:  fromEqnSt', fromEqnSt'', mkQDefSt, mkQuantDef, mkQuantDef', ec,

@balacij
Copy link
Collaborator Author

balacij commented Jul 9, 2025

[I have no idea why you're talking about 'approximation' above.]

Trying to explain why I was talking about 'approximation' shows me that I was just confused. We can safely ignore that question.

Whereas I suspect that the real problem is that we are not capturing the information that we need "the right way".

I certainly agree with that, too.

@balacij
Copy link
Collaborator Author

balacij commented Jul 9, 2025

I think part of the issue is that we don't know what the Quantity constraint means. Does it mean "is a quantity"? Or does it mean "represents a quantity"?

-- | A Quantity is an 'Idea' with a 'Space' and a 'Symbol'.
-- In theory, it should also restrict to being a part of 'MayHaveUnit', but that causes
-- all sorts of import cycles (or lots of orphans).
class (Idea c, HasSpace c, HasSymbol c) => Quantity c where

Whatever we decide on, the comment needs to be updated.

That being said, what differences between "represents a quantity" and "is a quantity" do you see?

I can vaguely see a difference: "is a quantity" means that the data types can be treated as if they were quantities/variables about specific dimensions, and "represents a quantity" means that data types strictly represent quantities, "quantities" are defined by those specific features (Idea, HasSpace, HasSymbol, May HaveUnit), and might impose extra restrictions about those dimensions (a quasi-type).

I'm not sure if I like the existence of Quantity at all. Why shouldn't quantities (variables) always be represented by the same type (QuantityDict at the moment, but DefinedQuantityDict preferred because it has the prose descriptions as well)?

Nor do we really know what QDefinition is supposed to embody. So it is really hard to know of those instances should be there or not.

&

I think of 'QDefinition's as specific solutions to calculating a quantity. i.e., its nature is about calculation, not about defining a symbol.

That a priori makes sense. Though I think that's what DataDefinitions are for. I think the case of QDefinition was when you are creating a new symbol, but you are also associating a way to compute it at the same time.

Hmm, now that's a surprising twist to me (that this is what DataDefinitions and QDefinitions were previously for). In that case, would QDefinition be a chunk at all? The comment for DataDefinition would also be a bit odd.

-- | A data definition is a 'QDefinition' that may have additional notes: 
-- the scope, any references (as 'DecRef's), maybe a derivation, a label ('ShortName'), a reference address, and other notes ('Sentence's).
data DataDefinition where
  DDE  :: SimpleQDef -> DDPkt -> DataDefinition
  DDME :: ModelQDef -> DDPkt -> DataDefinition
  
data DDPkt = DDPkt {
  _pktUID :: UID,
  _pktST  :: ScopeType,
  _pktDR  :: [DecRef],
  _pktMD  :: Maybe Derivation,
  _pktSN  :: ShortName,
  _pktS   :: String,
  _pktSS  :: [Sentence]
}

^ 'term' and 'abrv' are inherited from the QDef (which also inherits this information from its internal DefinedQuantityDict), but doesn't inherit the defn -- only the QDef has a defn that describes what the formula is (except this formula is

Similar to our recent discussion about IMs, GDs, and TMs wrapping "theories" with display/presentation information, I think DDs might be the same, except purely specialized for QDefinitions.

Taking a step back on all of these and rethinking their relationships is probably a good idea right about now...

@JacquesCarette
Copy link
Owner

'5 apples' is a quantity (of apples); '(n+k+3) apples' represents a quantity of apples. One is immediate knowledge, one is future knowledge. That's not the only difference, but it's a big one.

Whenever you're not sure between 'is' and 'represents', go stare at This painting.

I'm not sure if I like the existence of Quantity at all. Why shouldn't quantities (variables) always be represented by the same type (QuantityDict at the moment, but DefinedQuantityDict preferred because it has the prose descriptions as well)?

Because whatever a 'Quantity' is, it should be a promise of certain pieces of information being available. The exact representation should not matter. That a particular representation may in fact contain additional information most definitely should not matter.

Our important internal concepts should be 'information promises' and not concrete representations.

In all cases, the most important thing (whether it's QDefinition, DefinedQuantityDict or DataDefinition) is "what information does this structure promise to provide". At use-site, we then can use exactly those items that contain at least all the information that is needed to function properly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants