Closed Ant13731 closed 3 years ago
Agreed.
I've started implementing some changes, but I'm running into a problem that's more focused on design:
DataDefinitions, InstanceModels, TheoryModels, and GeneralDefinitions all use RefInfo
within their internal References
. This use of RefInfo
within an actual Reference shows up in the sources section of the table when each model or definition is generated. Removing this without doing anything would erase the extra RefInfo
from the SRS completely. Here is a data definition from GlassBR to show how the refInfo
function is being used to make a reference
with additional information.
dimLL :: DataDefinition
dimLL = dd dimLLQD [ref astm2009, refInfo campidelli $ Equation [7]] Nothing "dimlessLoad"
[qRef, aGrtrThanB, stdVals [modElas], hRef, gtfRef]
I have a few ideas on how we could go about remedying this:
Sentence
of references to the record type for definitions and models. This would probably have the lowest impact on the rest of drasil, but I'm not sure if we really want to encode that sort of thing directly into the type of models and definitions.[Reference]
) into something that takes references and any associated reference information (like [(Reference, RefInfo)]
). From there, it is an easy modification to the table generator to pass through the RefInfo
. This seems kind of hacky though and the HasReference
class would need to change. This would also require renaming that class, as it would no longer be holding just References
but RefInfo
as well.Sentences
, where each element is a reference that has been put into sentence form. This way, we can hold the RefInfo
along with reference UIDs
in a list. It would also involve changing the HasReference
class from fetching References to fetching Sentences
. I think this would be okay for the most part, but leaving it open to anything that is a Sentence
may be a little too flexible.I'm not sure what the best move here is. They all don't seem like great options in terms of reducing the complexity of referencing, but I don't want to leave out RefInfo
entirely from models/definitions.
First: we want structured information as much as possible. Sentence
is slightly better than String
, but not enough. Passing a Sentence
around should be a last resort when we decide that the only use we'll ever make with that information is display it - now and forever. This is not so with RefInfo
, so any Sentence
-based solution, is not a solution.
It seems to me that we want the "references" part in DataDefinitions (etc) to be 'decorated' references (as you show above). We most definitely shouldn't remove that information.
Yea, I think I see what you mean. So would a possible solution be to create and use a new decorated reference type, and then define that as part of the Referable class for when we need just the reference information? Maybe also a part of the HasReference class as well? Something like:
data DecRef = DR {ref :: Reference
ri :: RefInfo}
Just for those times when we need the extra information but aren't quite ready to use sentences?
We could certainly create such a type.
The problem is to decide what Referable
and HasReference
really mean. A DecRef
doesn't really have a reference, it is a reference. Similarly, things like sections and papers should be Referable
, but references themselves should be Referable
.
So References themselves should not be Referable
? I originally thought that Referable
was just anything that could be turned into a reference (and that references could be turned into references). But if we want to make the distinction between References
and things that are Referable
without breaking how references work, then I think there should be a little shuffling of the class structure.
Currently, we have the HasShortName
, HasRefAddress
, and Referable
classes. As of right now, the HasRefAddress
class isn't really used. Previous to the changes I made to Reference
, HasRefAddress
was used for some referencing functions, but not much else. Making References
an instance of the Referable
class reduced the need for seemingly duplicate functions. But if we want to remove that instance, then we might want the following to happen:
LblTypes
out of either a chunk or a reference. This way, we don't need the Referable
class to do this job. When putting any content that could become a reference into a database, some References
end up being fed to the function (which is expected and wanted). Because we want to make sure everything is a Reference
before we send it off to the chunk database, we call a blanket function that accepts both references and referables to output a list of guaranteed references. This is why I initially made References
an instance of Referable
.Referable
class depend on the HasRefAddress
and the new class from above since it really just combines the functionality of both into a convenient package. Something that doesn't have a reference address and label shouldn't be referable in the first place.I agree that DecRef
shouldn't be part of the HasReference
class, but maybe it could be a part of the above suggestions for classes (with all the same class instances). And then, we can provide a function that fetches the RefInfo
from only a DecRef
when needed.
What do you think?
I think Referable
ought to be anything that can be referenced - which is slightly different. We don't want pointers to pointers...
Yes, I am quite sure there will be a need for some rejigging - both what the code uses and maybe the classes. It might be that in places it is the code that incorrectly uses the member functions, rather than the classes being off.
I think your suggestions make sense - but are phrased a little too "operationally" for me. Could you give me what the 'meaning' of each changed/new class would be?
Yea, I agree. I thought about this a little bit more and I think that we might not need a new class, just that the existing HasRefAddress
class isn't what I thought it was. I think I was a little off in my design, so I'll try and go through my new idea. For the meanings of each class:
HasShortName
- Gets the default display name within the reference. This information is not overwritten when we use namedRef
on a Reference
, but instead will not be used for display purposes. I don't think this needs any immediate change, but having the ability to overwrite shortnames
may be something to consider in the future.HasRefAddress
- Gets the reference address (currently as a string) of a referable type or a reference. I'd like to think of this as being one of the requirements for something to be Referable
. After all, if a type doesn't have a reference address, Drasil will not know where to reference, so it cannot be referred to. Currently, this class isn't being used for what it was needed to do, because it doesn't actually get the LblType
out of an object. It does some weird things depending on the type (sometimes it gets UIDs
for References
and Citations
, but other times it gets a completely different thing as in ConceptInstances
). This is a large part of why Referable
is being used in the pointer-to-pointer scenario. Drasil can't use a String
to actually link up a reference to its referred object, it needs that extra information provided in LblType
. So rather than making a new class for getting label types, we should convert this one to give reference addresses in the form of LblTypes
so they can be reused throughout Drasil.Referable
- Gets the reference address as a LblType
and a String
. Initially, I was just going to write that Referable
should just be an "upgrade" to HasRefAddress
, and that a type must be a part of the HasUID
and HasRefAddress
classes in order to be a Referable
, but I'm looking through the documentation again and I'm not sure if this design is right either. Because if we change HasRefAddress
to return a LblType
instead of a String
, I think Referable
would just become a wrapper for HasRefAddress
.In clearer terms: Drasil doesn't really use reference adresses in the form of only Strings
at all. Even at the printing stage, Drasil most of the printer functions still use the LblType
of a Reference
. They can then use the string with its intended context. There is already a function that can unwrap a LblType
to get the String
form, so passing around LblTypes
in Drasil should work well.
I feel like I'm still learning more about Drasil's referencing (its a lot more complicated than I thought), but on the technical side of things, here is what I propose:
getRefAdd
within HasRefAddress
to be b -> LblType
from b -> String
. This allows us to carry the context of the reference address which means the Reference
type no longer needs to be Referable
.Referable
so that it depends on HasRefAddress
as follows:
class HasUID s, HasRefAddress s => Referable s where
refAdd :: s -> String -- This would call the unwrapper for LblType after calling getRefAdd
renderRef :: s -> LblType -- This would just call getRefAdd
Referable
types so that the renderRef
method is the same as getRefAdd
.I'm not sure if that last point is a good idea, but I think this might work smoothly enough. After these classes are cleared up, we can worry more about the DecRef
and maybe write a function to get the RefInfo
needed
Since
References
are being held in the chunk database for deferred lookup by UID, all of the attachedRefInfo
information shouldn't be with the actualReference
itself. We have already made theRef
sentence constructor do the work of holding any neededRefInfo
, similar to howCh
holds whether a term should be singular, plural, or short form.RefInfo
is treated as Sentence-level display information, where the user explicitly writes in that they wantRefInfo
to display at a certain point in a sentence.As of right now, any reference that enters the
ChunkDB
gets theRefInfo
value set toNone
(by callingref
on anything that isReferable
). So it doesn't really make sense to keep it as a part of theReference
type because it should not be used inside aReference
. Leaving it may cause unwanted behaviour, as a user might unknowingly putRefInfo
into aChunkDB
, causing all appearances of that reference to have the attachedRefInfo
when they only wanted it in one particular spot.In addition, this has the added benefit of getting rid of
RefProg.hs
, since we can put that datatype intoSentence.hs
. This design is similar to howCh
works, where all the Sentence-level stuff stays with theSentence
type.