From b282af35ad4b0bb8d90e517f4b9ff03c22234090 Mon Sep 17 00:00:00 2001 From: Lars-Dominik Braun Date: Wed, 7 Sep 2022 15:07:04 +0200 Subject: Copy-edit specification --- src/lib/Codec/Pesto/Graph.lhs | 96 ++++++++++++++++++++++++++----------------- 1 file changed, 59 insertions(+), 37 deletions(-) (limited to 'src/lib/Codec/Pesto/Graph.lhs') diff --git a/src/lib/Codec/Pesto/Graph.lhs b/src/lib/Codec/Pesto/Graph.lhs index a9d42a7..43142b6 100644 --- a/src/lib/Codec/Pesto/Graph.lhs +++ b/src/lib/Codec/Pesto/Graph.lhs @@ -45,7 +45,7 @@ both directives. > (between, next) = break isEnd stream > extract (_:xs) = extract xs -Start and end directive are removed from the extracted instructions. The +Start and end directives are removed from the extracted instructions. The directive “buonappetito” is optional at the end of a stream. > testExtract = [ @@ -63,62 +63,80 @@ Instructions surrounding the start and end directive are removed. The stream may contain multiple recipes. The start directive also ends the previous recipe and starts a new one. -> , extract [startDirective, Action "pour", endDirective, Action "foobar", startDirective, Annotation "something"] ~?= [[Action "pour"], [Annotation "something"]] -> , extract [startDirective, Action "heat", startDirective, Annotation "something"] ~?= [[Action "heat"], [Annotation "something"]] -> , extract [startDirective, Annotation "foobar", startDirective, endDirective] ~?= [[Annotation "foobar"], []] +> , extract [ +> startDirective +> , Action "pour" +> , endDirective +> , Action "foobar" +> , startDirective +> , Annotation "something"] +> ~?= [[Action "pour"], [Annotation "something"]] +> , extract [ +> startDirective +> , Action "heat" +> , startDirective +> , Annotation "something"] +> ~?= [[Action "heat"], [Annotation "something"]] +> , extract [ +> startDirective +> , Annotation "foobar" +> , startDirective +> , endDirective] +> ~?= [[Annotation "foobar"], []] > ] Each recipe’s stream of instructions drives a stack-based machine that transforms it into a directed graph. Think of the stack as your kitchen’s workspace that is used to prepare the food’s components. You can add new ingredients, perform -actions on them, put them aside and add them again. +actions on them, put them aside, and add them again. -This function processes a list of nodes, that is instructions uniquely identified -by an integer and returns the edges of the directed graph as a list of tuples. +This function processes a list of nodes, that is, instructions uniquely identified +by an integer, and returns the edges of the directed graph as a list of tuples. +> toGraph :: Nodes Instruction -> Edges > toGraph nodes = third $ foldl f (Nothing, [[]], []) nodes > where -Ingredients are simply added to the current workspace. They should for example +Ingredients are simply added to the current workspace. They should, for example, appear on the shopping list. > f ctx (i, Ingredient _) = addToStack ctx i -The same happens for for tools. However they are not part of the final product, -but used in the process of making it. For instance they do not appear on the -shopping list. `Time is a tool <#time-is-a-tool>`_. +The same happens for tools. However, they are not part of the final product +but are used in the process of making it. Thus, they do not appear on the +shopping list. `Time is considered a tool <#time-is-a-tool>`_. > f ctx (i, Tool _) = addToStack ctx i Actions take all ingredients and tools currently on the workspace, perform some -action with them and put the product back onto the workspace. +action with them, and put the product back onto the workspace. > f (_, stack:sx, edges) (i, Action _) = (Just i, [i]:stack:sx, edgesTo i stack ++ edges) > f (_, [], _) (_, Action _) = undefined -- never reached Results add a label to the current workspace’s contents and move them out of -the way. It should be a meaningful name, not just A and B obviously. -Consecutive Results add different labels to the same workspace. That’s useful +the way. It should be a meaningful name, not just A and B. +Consecutive results add different labels to the same workspace. That’s useful when an action yields multiple results at once that are processed in different ways. > f ctx (i, Result _) = consumeStack ctx i -Alternatives too add a label to the current workspace’s content, but they pick -one of things on the workspace and throw everything else away. This allows -adding optional or equivalent ingredients to a recipe (i.e. margarine or butter). +Alternatives, too, add a label to the current workspace’s content, but they pick +one of the things on the workspace and throw everything else away. This allows +adding optional or equivalent ingredients to a recipe (i.e., margarine or butter). > f ctx (i, Alternative _) = consumeStack ctx i References are similar to ingredients. They are used to add items from a -workspace labeled with Result or Alternative. More on that `in the next section +workspace labeled with ``Result`` or ``Alternative``. More on that `in the next section <#references>`_. > f ctx (i, Reference _) = addToStack ctx i Annotations add a description to any of the previous instructions. They can be used to provide more information about ingredients (so “hot water” becomes -``+water (hot)``, tools (``&oven (200 °C)``) or actions (``[cook] +``+water (hot)``, tools (``&oven (200 °C)``), or actions (``[cook] (until brown)``). > f ctx@(Nothing, _, _) (_, Annotation _) = ctx @@ -141,14 +159,14 @@ These are helper functions: > in (Just i, []:top:sx, edgesTo i top ++ edges) > edgesTo i = map (\x -> (x, i)) -Here are a few example of how this stack-machine works. Each edge is a tuple of +Here are a few examples of how this stack-machine works. Each edge is a tuple of two integer numbers. These are the nodes it connects, starting with zero. -Ingredient, Tool and Reference itself do not create any edges: +``Ingredient``, ``Tool``, and ``Reference`` itself do not create any edges: > testGraph = [ > cmpGraph "+ketchup &spoon *foobar" [] -But Action, Alternative and Result do in combination with them: +But ``Action``, ``Alternative`` and ``Result`` do in combination with them: > , cmpGraph "+foobar [barbaz]" [(0, 1)] > , cmpGraph "+foobar |barbaz" [(0, 1)] @@ -158,11 +176,12 @@ But Action, Alternative and Result do in combination with them: > , cmpGraph "+foobar [barbaz] +foobar >barbaz" [(0, 1), (1, 3), (2, 3)] > , cmpGraph "&foobar [barbaz] [C] >D" [(0, 1), (1, 2), (2, 3)] -If the stack is empty, i.e. it was cleared by a Result or Alternative +If the stack is empty, i.e. it was cleared by a ``Result`` or ``Alternative`` instruction, consecutive results or alternatives operate on the *previous*, non-empty stack. > , cmpGraph "+foobar >barbaz >C" [(0, 1), (0, 2)] +> , cmpGraph "+foobar >barbaz >C >D" [(0, 1), (0, 2), (0, 3)] > , cmpGraph "+foobar |barbaz |C" [(0, 1), (0, 2)] > , cmpGraph "+foobar >barbaz |C" [(0, 1), (0, 2)] @@ -173,7 +192,7 @@ Unless that stack too is empty. Then they do nothing: > , cmpGraph "(foobar) (foobar)" [] > , cmpGraph "[foobar]" [] -The Annotation instruction always creates an edge to the most-recently processed +The ``Annotation`` instruction always creates an edge to the most-recently processed node that was not an annotation. Thus two consecutive annotations create edges to the same node. @@ -195,30 +214,33 @@ Unknown directives or instructions are never connected to other nodes. References ++++++++++ -Results and alternatives can be referenced with the Reference instruction. -Resolving these references does not happen while buiding the graph, but -afterwards. This allows referencing an a result or alternative before its -definition with regard to the their processing order. +Results and alternatives can be referenced with the ``Reference`` instruction. +Resolving these references does not happen while building the graph but +afterward. This allows referencing a result or alternative before its +definition with regard to their processing order. -Resolving references is fairly simple: For every reference its object name a -case-insensitive looked is performed in a table containing all results and -alternatives. If it succeeds an edge from every result and alternative returned +Resolving references is fairly simple: For every reference’s object name, a +case-insensitive lookup is performed in a table containing all results and +alternatives. If it succeeds, an edge from every result and alternative returned to the reference in question is created. +> resolveReferences :: Nodes Instruction -> Edges > resolveReferences nodes = foldl f [] nodes > where -> f edges (i, ref@(Reference _)) = map (\x -> (x, i)) (findTarget nodes ref) ++ edges +> f edges (i, ref@(Reference _)) = map (\x -> (x, i)) (findTargets nodes ref) ++ edges > f edges _ = edges -> findTarget nodes (Reference (Quantity _ _ a)) = map fst $ filter (isTarget a) nodes +> findTargets :: Nodes Instruction -> Instruction -> [NodeId] +> findTargets nodes (Reference (Quantity _ _ a)) = map fst $ filter (isTarget a) nodes > where > lc = map toLower > isTarget dest (_, Result (Quantity _ _ x)) = lc x == lc dest -> isTarget dest (_, Alternative (Quantity _ _ x)) = lc x == lc dest +> isTarget dest (_, Alternative (Quantity _ _ x)) = lc x == lc dest > isTarget _ _ = False -> findTarget _ _ = [] +> findTargets _ _ = [] -References works before or after the result instruction. +References are position-independent and can be used before or after the +result instruction they are referencing. > testRef = [ > cmpGraphRef ">foobar *foobar" [(0, 1)] @@ -263,7 +285,7 @@ Appendix Find graph’s root node(s), that is a node without outgoing edges: > walkRoot nodes edges = let out = nub $ map fst edges -> in filter (\(x, _) -> notElem x out) nodes +> in filter (\(x, _) -> notElem x out) nodes Get all nodes with edges pointing towards nodeid -- cgit v1.2.3