-
Notifications
You must be signed in to change notification settings - Fork 26
Debugging in Drasil
When errors are thrown from Drasil programs, we will be given specific error messages in the logs. If the error message isn't familiar to you, it's best to generally search the entire code repository for that message to see what kind of error(s) could have occurred. Using grep
, we can search through the repo fairly easily!
A common and likely useful formation for using grep
commands to find errors thrown by Drasil is to use the structure:
grep "WordYouAreLookingFor" -r * --include "*.hs"
which will recursively search all files ending with the letters .hs
in the directory for occurrences of "WordYouAreLookingFor". There are some optional flags that may be useful:
-
-w
will only search for the whole word given. Whole words are determined by whitespace or non-letter characters. So words separated with a.
will still appear. BASH users may note that they may write the"*.hs"
as just*.hs
. For example, using the commandgrep "traceMGF" -r -w * --include "*.hs"
orgrep "traceMGF" -rw * --include "*.hs"
will return:
drasil-docLang/Drasil/DocumentLanguage/TraceabilityGraph.hs:traceMGF :: [LabelledContent] -> [Sentence] -> [Contents] -> [Section] -> Section
drasil-docLang/Drasil/DocumentLanguage/TraceabilityGraph.hs:traceMGF refs trailing otherContents = SRS.traceyMandG (traceMIntro refs trailing : otherContents)
drasil-docLang/Drasil/DocumentLanguage.hs:import qualified Drasil.DocumentLanguage.TraceabilityGraph as TG (traceMGF)
drasil-docLang/Drasil/DocumentLanguage.hs:mkTraceabilitySec (TraceabilityProg progs) si = TG.traceMGF trace
-
--color
will highlight the word searched in a different colour. This is useful for largergrep
searches, where each occurrence is not instantly apparent.
Let's say you are working on adding a new section to an example (specifically, we will be using DblPendulum
for code excerpts, but the same concepts will apply across Drasil). When you try to compile, you receive the following error message:
Reference: parnasClements1986 not found in ReferenceMap
It will be quite difficult to manually search through all the files to find this exact error message, so let's try using grep
on a small part of the error message. Using grep "not found in" -r * --include "*.hs"
(meaning that I want to traverse all files, looking only through the .hs
files for lines containing the characters "not found in") shows us that the errors starts in code/drasil-database/Database/Drasil/ChunkDB.hs
:
-- | Looks up a 'UID' in a 'UMap' table. If nothing is found, an error is thrown.
uMapLookup :: String -> String -> UID -> UMap a -> a
uMapLookup tys ms u t = getFM $ Map.lookup u t
where getFM = maybe (error $ tys ++ ": " ++ u ++ " not found in " ++ ms) fst
-- | Looks up a 'UID' in the symbol table from the 'ChunkDB'. If nothing is found, an error is thrown.
symbResolve :: ChunkDB -> UID -> QuantityDict
symbResolve m x = uMapLookup "Symbol" "SymbolMap" x $ symbolTable m
We can see that uMapLookup
is the function that actually throws the error, but it's thrown only when a lookup fails for some map (for example, the symbResolve
function resolves QuantityDict
s from the SymbolMap
of a ChunkDB
using uMapLookup
, so it can also cause errors).
Looking around the surrounding code (which will not be added to the snippet above for the sake of conserving space), we can see that when "X not found in Y-Map" errors occur, it's usually due to something not being in some ChunkDB
(the X
represents the UID
of the missing item, and the Y
represents the Map
from which it is expected but does not exist in).
Using a similar grep
to the above (searching with ChunkDB
), we find the type declaration in code/drasil-database/Database/Drasil/ChunkDB.hs
:
-- | Our chunk databases. \Must contain all maps needed in an example.\
-- In turn, these maps must contain every chunk definition or concept
-- used in its respective example, else an error is thrown.
data ChunkDB = CDB { symbolTable :: SymbolMap
, termTable :: TermMap
, defTable :: ConceptMap
, _unitTable :: UnitMap
, _traceTable :: TraceMap
, _refbyTable :: RefbyMap
, _dataDefnTable :: DatadefnMap
, _insmodelTable :: InsModelMap
, _gendefTable :: GendefMap
, _theoryModelTable :: TheoryModelMap
, _conceptinsTable :: ConceptInstanceMap
, _sectionTable :: SectionMap
, _labelledcontentTable :: LabelledContentMap
, _refTable :: ReferenceMap
} --TODO: Expand and add more databases
The ChunkDB
is the "Chunk Database", containing all "chunk definitions and concepts" for a specific "system" (example). It contains many kinds of Map
s from UIDs to various chunks.
This means that some example (likely the named one throwing the error in the first place) is missing some chunk information in it's ChunkDB
!
To resolve this, we generally want to:
-
Find where the thing we're missing was created - Again, I like to do this using
grep
usinggrep "X" -r * --include "*.hs"
. Taking the example ofparnasClements1986
, we get:
home:~/Programming/Drasil/code$ grep "parnasClements1986" -r * --include *.hs
drasil-data/Data/Drasil/Citations.hs: parnasClements1986, smithLai2005, lineSource, pointSource :: Citation
drasil-data/Data/Drasil/Citations.hs:parnasClements1986 = cArticle [dParnas, pcClements]
drasil-data/Data/Drasil/Citations.hs: "parnasClements1986"
drasil-docLang/Drasil/Sections/Introduction.hs:import Data.Drasil.Citations (parnasClements1986)
drasil-docLang/Drasil/Sections/Introduction.hs: S "Parnas and Clements point out", refS parnasClements1986 `sC`
drasil-example/Drasil/GlassBR/References.hs:import Data.Drasil.Citations (campidelli, koothoor2013, smithLai2005, parnasClements1986)
drasil-example/Drasil/GlassBR/References.hs: astm2012, beasonEtAl1998, parnasClements1986]
drasil-example/Drasil/SSP/References.hs:import Data.Drasil.Citations (jnlCGJ, koothoor2013, parnasClements1986, smithLai2005)
drasil-example/Drasil/SSP/References.hs:citations = [chen2005, parnasClements1986, koothoor2013,
drasil-example/Drasil/NoPCM/References.hs: parnasClements1986, smithLai2005)
drasil-example/Drasil/NoPCM/References.hs:citations = [incroperaEtAl2007, koothoor2013, lightstone2012, parnasClements1986, smithLai2005]
drasil-example/Drasil/GamePhysics/References.hs:import Data.Drasil.Citations (cartesianWiki, koothoor2013, parnasClements1986,
drasil-example/Drasil/GamePhysics/References.hs:citations = [parnas1978, sciComp2013, chaslesWiki, parnasClements1986,
drasil-example/Drasil/SWHS/References.hs: parnasClements1986, smithLai2005, citeRefs) where
drasil-example/Drasil/SWHS/References.hs:import Data.Drasil.Citations (koothoor2013, parnasClements1986, smithLai2005)
drasil-example/Drasil/SWHS/References.hs:citations = [bueche1986, incroperaEtAl2007, koothoor2013, lightstone2012, parnasClements1986,
Here, we can see that parnasClements1986
was created in drasil-data/Data/Drasil/Citations.hs
(we also see some examples of imports of it, so that will be helpful later too).
If no suitable results appeared, then it's likely that you will either need to create the desired function or that a UID
reference was incorrect.
2. Find where we were supposed to place it in the ChunkDB
of that system/example - For example, with DblPendulum, we instantiate our ChunkDB
in Body.hs
here:
symbMap :: ChunkDB
symbMap = cdb (map qw iMods ++ map qw symbols)
(nw newtonSLR : nw pendulumTitle : nw mass : nw len : nw kilogram : nw inValue : nw newton : nw degree : nw radian
: nw unitVect : nw unitVectj : [nw errMsg, nw program] ++ map nw symbols ++
map nw doccon ++ map nw doccon' ++ map nw physicCon ++ map nw mathcon ++ map nw physicCon' ++
map nw physicscon ++ concepts ++ map nw physicalcon ++ map nw acronyms ++ map nw symbols ++ map nw [metre, hertz])
(map cw iMods ++ srsDomains) (map unitWrapper [metre, second, newton, kilogram, degree, radian, hertz]) dataDefs
iMods genDefns tMods concIns [] [] allRefs
-
Figure out which list we should placing it in - You will need to analyze the error message for which
Map
it is related to, and then you will need to know how thecdb
smart constructor works. This can be done through the Haddock documentation or by usinggrep
again. For ease of reference, the declaration forcdb
is as follows:
cdb :: (Quantity q, MayHaveUnit q, Idea t, Concept c, IsUnit u) =>
[q] -> [t] -> [c] -> [u] -> [DataDefinition] -> [InstanceModel] ->
[GenDefn] -> [TheoryModel] -> [ConceptInstance] -> [Section] ->
[LabelledContent] -> [Reference] -> ChunkDB
cdb s t c u d ins gd tm ci sect lc r = CDB (symbolMap s) (termMap t) (conceptMap c)
(unitMap u) Map.empty Map.empty (idMap d) (idMap ins) (idMap gd) (idMap tm)
(idMap ci) (idMap sect) (idMap lc) (idMap r)
Looking at the type signature + surrounding comments are very helpful for this.
4. Add it to that chunk map - This step heavily depends on the example, but we usually can just prepend it to the list of references. In this case, there is an allRefs
list inside of Body.hs
:
allRefs :: [Reference]
allRefs = nub (assumpRefs ++ bodyRefs ++ figRefs ++ goalRefs ++ dataDefRefs ++ genDefRefs
++ iModRefs ++ tModRefs ++ citeRefs ++ reqRefs ++ secRefs)
We know parnasClements1986
is a Citation
from our above grep
search, so we look for the corresponding reference function, citeRefs
:
citeRefs :: [Reference]
citeRefs = map ref citations
We then look where citations
is defined and finally add our desired reference:
citations :: BibRef
citations = [accelerationWiki, velocityWiki, hibbeler2004, cartesianWiki, parnasClements1986]
Like learning any new language, getting started with grammar in Drasil is sometimes tough and a little confusing. To help new users jump in to working with Drasil, this section will note a variety of issues that can occur when starting out.
Often in Drasil, duplicate periods can crop up in seemingly mysterious ways. Through a mix of automatically generated content and the information that the user may input into an example, keeping track of punctuation has been an increasingly complicated task. The language of Drasil has seen consistent growth in this respect, and this section will demonstrate some of the common culprits of duplicate or missing periods.
The first step in any of these grammatically related problems should always be to double check the user input. Before we even get into the different kinds of functions available for use, making sure that a sneaky hard-coded period has not cropped up is key to having an enjoyable editing experience. This can be done in many different ways, most notably:
- Using
grep
orregrep
to search for periods. It may also be worthwhile to usegrep
including the last word before the period or quotation marks after the period, as using grep on just.
will also return all instances of the composition function native to Haskell. - Use
grep
on some words near the offending period. Often, there will be functions that are used in place of literal strings (meaning that thegrep
may fail to work if you only look for one certain word or phrase that happened to be replaced by a function). Try to avoid looking with words likeof
,a
,and
,the
, as those are often functions in the form of combinators and will not pattern match with thegrep
search. - Searching through the code manually and trying to find the spare period.
Next, we will introduce some common functions that include sentences in them. These are also very easy to mix up, so close attention is key:
- TODO
TODO
TODO
- Home
- Getting Started
- Documentation (of Drasil specifics)
- Design
-
Readings
- Drasil Papers and Documents
- Related Work and Inspiration
- Writing Documentation
- Compression as a Means to Learn Structure
- Glossary, Taxonomy, Ontology
- Grounded Theory
- Model Driven Scrapbook
- Model Transformation Languages
- ODE Definitions
- The Code Generator
- Suggested Reading
- Sustainability
- Productivity
- Reuse
- Formal Concept Analysis
- Generative Programming
- Software Documentation
- Units and Quantities
- Misc.
- WIP Projects