module Drasil.Website.Analysis where
import Language.Drasil
analysisSec :: FilePath -> FilePath -> FilePath -> FilePath -> [String] -> Section
analysisSec :: FilePath
-> FilePath -> FilePath -> FilePath -> [FilePath] -> Section
analysisSec analysisPath :: FilePath
analysisPath typePath :: FilePath
typePath clsIPath :: FilePath
clsIPath graphPath :: FilePath
graphPath pkgs :: [FilePath]
pkgs =
Sentence -> [Contents] -> [Section] -> Reference -> Section
section Sentence
drasilAnalysisTitle
[Sentence -> Contents
mkParagraph Sentence
analysisIntro]
[FilePath -> Section
dataTableSec FilePath
analysisPath, FilePath -> FilePath -> [FilePath] -> Section
tableOfGraphsSec FilePath
typePath FilePath
clsIPath [FilePath]
pkgs,
FilePath -> [FilePath] -> Section
graphSec FilePath
graphPath ([FilePath] -> Section) -> [FilePath] -> Section
forall a b. (a -> b) -> a -> b
$ (FilePath -> FilePath) -> [FilePath] -> [FilePath]
forall a b. (a -> b) -> [a] -> [b]
map ("drasil-" FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++) [FilePath]
pkgs]
(Reference -> Section) -> Reference -> Section
forall a b. (a -> b) -> a -> b
$ FilePath -> Sentence -> Reference
makeSecRef "Analysis" (Sentence -> Reference) -> Sentence -> Reference
forall a b. (a -> b) -> a -> b
$ FilePath -> Sentence
S "Analysis"
drasilAnalysisTitle :: Sentence
drasilAnalysisTitle :: Sentence
drasilAnalysisTitle = FilePath -> Sentence
S "Analysis of Drasil"
analysisIntro :: Sentence
analysisIntro :: Sentence
analysisIntro = FilePath -> Sentence
S "This section contains an graphs and tables that may be used to analyze the \
\structure of the Drasil framework. Here, we will explore the relationship between data types, \
\classes, and instances of those classes within Drasil, as well as the structure of individual \
\Drasil packages."
analysisRefs :: FilePath -> FilePath -> FilePath -> FilePath -> [String] -> [Reference]
analysisRefs :: FilePath
-> FilePath -> FilePath -> FilePath -> [FilePath] -> [Reference]
analysisRefs analysisPath :: FilePath
analysisPath typePath :: FilePath
typePath clsIPath :: FilePath
clsIPath graphPath :: FilePath
graphPath pkgs :: [FilePath]
pkgs =
[FilePath -> Reference
dataTableHTMLRef FilePath
analysisPath, FilePath -> Reference
dataTableCSVRef FilePath
analysisPath]
[Reference] -> [Reference] -> [Reference]
forall a. [a] -> [a] -> [a]
++ (FilePath -> Reference) -> [FilePath] -> [Reference]
forall a b. (a -> b) -> [a] -> [b]
map (FilePath -> FilePath -> FilePath -> FilePath -> Reference
getGraphsInTableRef "datatype" "" FilePath
typePath) [FilePath]
pkgs
[Reference] -> [Reference] -> [Reference]
forall a. [a] -> [a] -> [a]
++ (FilePath -> Reference) -> [FilePath] -> [Reference]
forall a b. (a -> b) -> [a] -> [b]
map (FilePath -> FilePath -> FilePath -> FilePath -> Reference
getGraphsInTableRef "classInst" "" FilePath
clsIPath) [FilePath]
pkgs
[Reference] -> [Reference] -> [Reference]
forall a. [a] -> [a] -> [a]
++ (FilePath -> Reference) -> [FilePath] -> [Reference]
forall a b. (a -> b) -> [a] -> [b]
map (FilePath -> FilePath -> FilePath -> FilePath -> Reference
getGraphsInTableRef "datatype" "circo_" FilePath
typePath) [FilePath]
pkgs
[Reference] -> [Reference] -> [Reference]
forall a. [a] -> [a] -> [a]
++ (FilePath -> Reference) -> [FilePath] -> [Reference]
forall a b. (a -> b) -> [a] -> [b]
map (FilePath -> FilePath -> FilePath -> FilePath -> Reference
getGraphsInTableRef "classInst" "circo_" FilePath
clsIPath) [FilePath]
pkgs
[Reference] -> [Reference] -> [Reference]
forall a. [a] -> [a] -> [a]
++ FilePath -> [FilePath] -> [Reference]
drasilDepGraphRefs FilePath
graphPath ((FilePath -> FilePath) -> [FilePath] -> [FilePath]
forall a b. (a -> b) -> [a] -> [b]
map ("drasil-" FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++) [FilePath]
pkgs)
dataTableSec :: FilePath -> Section
dataTableSec :: FilePath -> Section
dataTableSec path :: FilePath
path =
Sentence -> [Contents] -> [Section] -> Reference -> Section
section Sentence
dataTableTitle
[Sentence -> Contents
mkParagraph (Sentence -> Contents) -> Sentence -> Contents
forall a b. (a -> b) -> a -> b
$ FilePath -> Sentence
dataTableDesc FilePath
path]
[] (Reference -> Section) -> Reference -> Section
forall a b. (a -> b) -> a -> b
$ FilePath -> Sentence -> Reference
makeSecRef "DataTable" (Sentence -> Reference) -> Sentence -> Reference
forall a b. (a -> b) -> a -> b
$ FilePath -> Sentence
S "DataTable"
dataTableTitle :: Sentence
dataTableTitle :: Sentence
dataTableTitle = FilePath -> Sentence
S "Intersections of Types and Classes"
dataTableDesc :: FilePath -> Sentence
dataTableDesc :: FilePath -> Sentence
dataTableDesc path :: FilePath
path = FilePath -> Sentence
S "This" Sentence -> Sentence -> Sentence
+:+ Reference -> Sentence -> Sentence
forall r.
(HasUID r, HasRefAddress r, HasShortName r) =>
r -> Sentence -> Sentence
namedRef (FilePath -> Reference
dataTableHTMLRef FilePath
path) (FilePath -> Sentence
S "Data Table") Sentence -> Sentence -> Sentence
+:+
FilePath -> Sentence
S "is generated by Drasil to keep track of all the different types, classes, and where they intersect through instances. \
\The rows are organized in order of Drasil packages, modules, and data types. \
\The data types are further separated by their composition; those labelled \
\Data Type are completely new types created and used in Drasil, while Newtype Types are \
\type synonyms. All of the classes in Drasil are defined as \
\column headers, starting from Haskell-native classes like Eq and going through every \
\unique Drasil-defined class. A box marked with \
\'YYYY' symbolizes the file location of where that particular data type is an instance of a particular class. \
\There is also a" Sentence -> Sentence -> Sentence
+:+ Reference -> Sentence -> Sentence
forall r.
(HasUID r, HasRefAddress r, HasShortName r) =>
r -> Sentence -> Sentence
namedRef (FilePath -> Reference
dataTableCSVRef FilePath
path) (FilePath -> Sentence
S "downloadable version") Sentence -> Sentence -> Sentence
+:+ FilePath -> Sentence
S "of the Data Table available as a .csv file."
dataTableHTMLRef, dataTableCSVRef :: FilePath -> Reference
dataTableHTMLRef :: FilePath -> Reference
dataTableHTMLRef path :: FilePath
path = FilePath -> FilePath -> ShortName -> Reference
makeURI "dataTableHTML" (FilePath
path FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ "ClassInstDep/DataTable.html") (Sentence -> ShortName
shortname' (Sentence -> ShortName) -> Sentence -> ShortName
forall a b. (a -> b) -> a -> b
$ FilePath -> Sentence
S "dataTableHTML")
dataTableCSVRef :: FilePath -> Reference
dataTableCSVRef path :: FilePath
path = FilePath -> FilePath -> ShortName -> Reference
makeURI "dataTableCSV" (FilePath
path FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ "ClassInstDep/DataTable.csv") (Sentence -> ShortName
shortname' (Sentence -> ShortName) -> Sentence -> ShortName
forall a b. (a -> b) -> a -> b
$ FilePath -> Sentence
S "dataTableCSV")
tableOfGraphsSec :: FilePath -> FilePath -> [String] -> Section
tableOfGraphsSec :: FilePath -> FilePath -> [FilePath] -> Section
tableOfGraphsSec typePath :: FilePath
typePath clsIPath :: FilePath
clsIPath pkgs :: [FilePath]
pkgs =
Sentence -> [Contents] -> [Section] -> Reference -> Section
section Sentence
tableOfGraphsTitle
[Sentence -> Contents
mkParagraph Sentence
tableOfGraphsDescType, Sentence -> Contents
mkParagraph Sentence
tableOfGraphsDescClassInst, FilePath -> FilePath -> [FilePath] -> Contents
mkGraphsTable FilePath
typePath FilePath
clsIPath [FilePath]
pkgs]
[] (Reference -> Section) -> Reference -> Section
forall a b. (a -> b) -> a -> b
$ FilePath -> Sentence -> Reference
makeSecRef "TypeAndClassGraphs" (Sentence -> Reference) -> Sentence -> Reference
forall a b. (a -> b) -> a -> b
$ FilePath -> Sentence
S "TypeAndClassGraphs"
tableOfGraphsTitle :: Sentence
tableOfGraphsTitle :: Sentence
tableOfGraphsTitle = FilePath -> Sentence
S "Table of Graphs"
graphTable :: String -> FilePath -> String -> FilePath -> [String] -> [[Sentence]]
graphTable :: FilePath
-> FilePath -> FilePath -> FilePath -> [FilePath] -> [[Sentence]]
graphTable knd1 :: FilePath
knd1 path1 :: FilePath
path1 knd2 :: FilePath
knd2 path2 :: FilePath
path2 = (FilePath -> [Sentence]) -> [FilePath] -> [[Sentence]]
forall a b. (a -> b) -> [a] -> [b]
map (FilePath
-> FilePath -> FilePath -> FilePath -> FilePath -> [Sentence]
graphTableEntry FilePath
knd1 FilePath
path1 FilePath
knd2 FilePath
path2)
graphTableEntry :: String -> FilePath -> String -> FilePath -> String -> [Sentence]
graphTableEntry :: FilePath
-> FilePath -> FilePath -> FilePath -> FilePath -> [Sentence]
graphTableEntry knd1 :: FilePath
knd1 path1 :: FilePath
path1 knd2 :: FilePath
knd2 path2 :: FilePath
path2 pkg :: FilePath
pkg =
[Reference -> Sentence -> Sentence
forall r.
(HasUID r, HasRefAddress r, HasShortName r) =>
r -> Sentence -> Sentence
namedRef (FilePath -> FilePath -> FilePath -> FilePath -> Reference
getGraphsInTableRef FilePath
knd1 "" FilePath
path1 FilePath
pkg) (FilePath -> Sentence
S "drasil-" Sentence -> Sentence -> Sentence
:+: FilePath -> Sentence
S FilePath
pkg Sentence -> Sentence -> Sentence
+:+ FilePath -> Sentence
S "Types"),
Reference -> Sentence -> Sentence
forall r.
(HasUID r, HasRefAddress r, HasShortName r) =>
r -> Sentence -> Sentence
namedRef (FilePath -> FilePath -> FilePath -> FilePath -> Reference
getGraphsInTableRef FilePath
knd2 "" FilePath
path2 FilePath
pkg) (FilePath -> Sentence
S "drasil-" Sentence -> Sentence -> Sentence
:+: FilePath -> Sentence
S FilePath
pkg Sentence -> Sentence -> Sentence
+:+ FilePath -> Sentence
S "Class Instances")]
getGraphsInTableRef :: String -> String -> FilePath -> String -> Reference
getGraphsInTableRef :: FilePath -> FilePath -> FilePath -> FilePath -> Reference
getGraphsInTableRef knd :: FilePath
knd prfx :: FilePath
prfx path :: FilePath
path pkg :: FilePath
pkg = FilePath -> FilePath -> ShortName -> Reference
makeURI (FilePath
knd FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ FilePath
pkg FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ FilePath
prfx FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ "graph") (FilePath
path FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ FilePath
prfx FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ FilePath
pkg FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ ".svg") (ShortName -> Reference) -> ShortName -> Reference
forall a b. (a -> b) -> a -> b
$ Sentence -> ShortName
shortname' (Sentence -> ShortName) -> Sentence -> ShortName
forall a b. (a -> b) -> a -> b
$ FilePath -> Sentence
S (FilePath -> Sentence) -> FilePath -> Sentence
forall a b. (a -> b) -> a -> b
$ FilePath
pkg FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ FilePath
prfx FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ "graph"
tableOfGraphsDescType :: Sentence
tableOfGraphsDescType :: Sentence
tableOfGraphsDescType = FilePath -> Sentence
S "The following" Sentence -> Sentence -> Sentence
+:+ Reference -> Sentence -> Sentence
forall r.
(HasUID r, HasRefAddress r, HasShortName r) =>
r -> Sentence -> Sentence
namedRef Reference
tableGraphRef (FilePath -> Sentence
S "Table of Type and Class Instance Graphs") Sentence -> Sentence -> Sentence
+:+ FilePath -> Sentence
S "is another artifact generated by Drasil. \
\The type graphs explore the dependency of data types upon each other. These graphs include record-defined types, newtype wrappers, \
\and data types built from other other types. For these graphs, a node with a black outline signifies that the type is not defined in that package, \
\but still used in the creation of other types (this includes Haskell-native types since we do not redefine those). A red outline signifies \
\that the type was created using Haskell's 'type' syntax, while dark green means the type was made using 'newtype' syntax. A purple border shows \
\that the type uses constructor syntax and cyan is used for types written with record syntax. The arrow starts from the base types at the tip and \
\follows through so that dependent types are placed at the tail. Usually, this means that those types at the tail may contain the type at the tip of the arrow."
tableOfGraphsDescClassInst :: Sentence
tableOfGraphsDescClassInst :: Sentence
tableOfGraphsDescClassInst = FilePath -> Sentence
S "The class instance graphs aim to look at the structure of classes, data types, and the interactions \
\between those two. Specifically, each arrow represents the given type as an instance of a given class. The tip of the arrow points to the class, and the \
\tail specifies the type that is an instance of the tip's class. For clarity in analyzing the structure, classes defined in the graph's package are coloured magenta, \
\classes that are used but not defined in the package are rendered pink (includes Haskell-native classes), and data types are rendered with a turquoise border."
mkGraphsTable :: FilePath -> FilePath -> [String] -> Contents
mkGraphsTable :: FilePath -> FilePath -> [FilePath] -> Contents
mkGraphsTable typePath :: FilePath
typePath clsInstPath :: FilePath
clsInstPath pkgs :: [FilePath]
pkgs = LabelledContent -> Contents
LlC (LabelledContent -> Contents) -> LabelledContent -> Contents
forall a b. (a -> b) -> a -> b
$ Reference -> RawContent -> LabelledContent
llcc Reference
tableGraphRef (RawContent -> LabelledContent) -> RawContent -> LabelledContent
forall a b. (a -> b) -> a -> b
$ [Sentence] -> [[Sentence]] -> Sentence -> Bool -> RawContent
Table
[FilePath -> Sentence
S "Generated Type Graphs", FilePath -> Sentence
S "Generated Class Instance Graphs"]
(FilePath
-> FilePath -> FilePath -> FilePath -> [FilePath] -> [[Sentence]]
graphTable "datatype" FilePath
typePath "classInst" FilePath
clsInstPath [FilePath]
pkgs)
(FilePath -> Sentence
S "Type Graphs") Bool
True
tableGraphRef :: Reference
tableGraphRef :: Reference
tableGraphRef = FilePath -> Reference
makeTabRef "TableOfGraphs"
graphSec :: FilePath -> [String] -> Section
graphSec :: FilePath -> [FilePath] -> Section
graphSec path :: FilePath
path pkgs :: [FilePath]
pkgs =
Sentence -> [Contents] -> [Section] -> Reference -> Section
section Sentence
packDepGraphTitle
(Sentence -> Contents
mkParagraph (FilePath -> Sentence
S FilePath
graphSecIntro) Contents -> [Contents] -> [Contents]
forall a. a -> [a] -> [a]
: [Contents]
displayGraphs [Contents] -> [Contents] -> [Contents]
forall a. [a] -> [a] -> [a]
++ [Contents]
listOfLinkedGraphs)
[] (Reference -> Section) -> Reference -> Section
forall a b. (a -> b) -> a -> b
$ FilePath -> Sentence -> Reference
makeSecRef "DependencyGraphs" (Sentence -> Reference) -> Sentence -> Reference
forall a b. (a -> b) -> a -> b
$ FilePath -> Sentence
S "Dependency Graphs"
where
displayGraphs :: [Contents]
displayGraphs = (FilePath -> Contents) -> [FilePath] -> [Contents]
forall a b. (a -> b) -> [a] -> [b]
map (FilePath -> FilePath -> Contents
dependencyGraphs FilePath
path) ["drasil-website"]
listOfLinkedGraphs :: [Contents]
listOfLinkedGraphs = [UnlabelledContent -> Contents
UlC (UnlabelledContent -> Contents) -> UnlabelledContent -> Contents
forall a b. (a -> b) -> a -> b
$ RawContent -> UnlabelledContent
ulcc (RawContent -> UnlabelledContent)
-> RawContent -> UnlabelledContent
forall a b. (a -> b) -> a -> b
$ FilePath -> [FilePath] -> RawContent
folderList FilePath
path [FilePath]
pkgs]
packDepGraphTitle :: Sentence
packDepGraphTitle :: Sentence
packDepGraphTitle = FilePath -> Sentence
S "Package Dependency Graphs"
graphSecIntro :: String
graphSecIntro :: FilePath
graphSecIntro = "The below list contains all of the different packages used to build the Drasil Framework. \
\Each package and its dependencies are displayed in the form of a graph, with the tail of the arrow being the dependent module, \
\and the tip of the arrow being the base module. In other words, the tip builds off of (or relies on) the tail to work. \
\Links are available to a pdf version of each package's dependency graph at the bottom. For example, the graph for the website package \
\is shown below. Each section is made from different modules that come together under the Drasil.Website.Body module and then \
\are generated by Drasil.Website.Main. This result shows that the package structure has a pyramid-like hierarchy."
dependencyGraphs :: FilePath -> String -> Contents
dependencyGraphs :: FilePath -> FilePath -> Contents
dependencyGraphs path :: FilePath
path pkg :: FilePath
pkg = LabelledContent -> Contents
LlC (LabelledContent -> Contents) -> LabelledContent -> Contents
forall a b. (a -> b) -> a -> b
$ Reference -> RawContent -> LabelledContent
llcc (FilePath -> Reference
makeFigRef (FilePath -> Reference) -> FilePath -> Reference
forall a b. (a -> b) -> a -> b
$ "Figure" FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ FilePath
pkg) (RawContent -> LabelledContent) -> RawContent -> LabelledContent
forall a b. (a -> b) -> a -> b
$ Sentence -> FilePath -> RawContent
fig (FilePath -> Sentence
S (FilePath -> Sentence) -> FilePath -> Sentence
forall a b. (a -> b) -> a -> b
$ "Package: " FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ FilePath
pkg) (FilePath -> RawContent) -> FilePath -> RawContent
forall a b. (a -> b) -> a -> b
$ FilePath -> FilePath -> FilePath
drasilDisplayDepGraphPath FilePath
path FilePath
pkg
drasilDisplayDepGraphPath :: FilePath -> FilePath -> String
drasilDisplayDepGraphPath :: FilePath -> FilePath -> FilePath
drasilDisplayDepGraphPath path :: FilePath
path fldr :: FilePath
fldr = FilePath
path FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ FilePath
fldr FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ ".png"
drasilDepGraphPathsPDF :: FilePath -> [String] -> [String]
drasilDepGraphPathsPDF :: FilePath -> [FilePath] -> [FilePath]
drasilDepGraphPathsPDF path :: FilePath
path = (FilePath -> FilePath) -> [FilePath] -> [FilePath]
forall a b. (a -> b) -> [a] -> [b]
map (\x :: FilePath
x -> FilePath
path FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ FilePath
x FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ ".pdf")
drasilDepGraphRefs :: FilePath -> [String] -> [Reference]
drasilDepGraphRefs :: FilePath -> [FilePath] -> [Reference]
drasilDepGraphRefs path :: FilePath
path pkgs :: [FilePath]
pkgs = (FilePath -> FilePath -> Reference)
-> [FilePath] -> [FilePath] -> [Reference]
forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith (\x :: FilePath
x y :: FilePath
y -> FilePath -> FilePath -> ShortName -> Reference
makeURI FilePath
x FilePath
y (ShortName -> Reference) -> ShortName -> Reference
forall a b. (a -> b) -> a -> b
$ Sentence -> ShortName
shortname' (Sentence -> ShortName) -> Sentence -> ShortName
forall a b. (a -> b) -> a -> b
$ FilePath -> Sentence
S FilePath
x) [FilePath]
pkgs ([FilePath] -> [Reference]) -> [FilePath] -> [Reference]
forall a b. (a -> b) -> a -> b
$ FilePath -> [FilePath] -> [FilePath]
drasilDepGraphPathsPDF FilePath
path [FilePath]
pkgs
folderList :: FilePath -> [String] -> RawContent
folderList :: FilePath -> [FilePath] -> RawContent
folderList path :: FilePath
path pkgs :: [FilePath]
pkgs = ListType -> RawContent
Enumeration (ListType -> RawContent) -> ListType -> RawContent
forall a b. (a -> b) -> a -> b
$ [(ItemType, Maybe FilePath)] -> ListType
Bullet ([(ItemType, Maybe FilePath)] -> ListType)
-> [(ItemType, Maybe FilePath)] -> ListType
forall a b. (a -> b) -> a -> b
$ [ItemType] -> [Maybe FilePath] -> [(ItemType, Maybe FilePath)]
forall a b. [a] -> [b] -> [(a, b)]
zip (FilePath -> [FilePath] -> [ItemType]
folderListItems FilePath
path [FilePath]
pkgs) ([Maybe FilePath] -> [(ItemType, Maybe FilePath)])
-> [Maybe FilePath] -> [(ItemType, Maybe FilePath)]
forall a b. (a -> b) -> a -> b
$ Maybe FilePath -> [Maybe FilePath]
forall a. a -> [a]
repeat Maybe FilePath
forall a. Maybe a
Nothing
folderListItems :: FilePath -> [String] -> [ItemType]
folderListItems :: FilePath -> [FilePath] -> [ItemType]
folderListItems path :: FilePath
path pkgs :: [FilePath]
pkgs = (Sentence -> ItemType) -> [Sentence] -> [ItemType]
forall a b. (a -> b) -> [a] -> [b]
map Sentence -> ItemType
Flat ([Sentence] -> [ItemType]) -> [Sentence] -> [ItemType]
forall a b. (a -> b) -> a -> b
$ (Reference -> Sentence -> Sentence)
-> [Reference] -> [Sentence] -> [Sentence]
forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith Reference -> Sentence -> Sentence
forall r.
(HasUID r, HasRefAddress r, HasShortName r) =>
r -> Sentence -> Sentence
namedRef (FilePath -> [FilePath] -> [Reference]
drasilDepGraphRefs FilePath
path [FilePath]
pkgs) ([Sentence] -> [Sentence]) -> [Sentence] -> [Sentence]
forall a b. (a -> b) -> a -> b
$ (FilePath -> Sentence) -> [FilePath] -> [Sentence]
forall a b. (a -> b) -> [a] -> [b]
map FilePath -> Sentence
S [FilePath]
pkgs