Drop vendored tree

This commit is contained in:
Mark Eibes 2022-08-29 15:26:55 +02:00
parent 1e7e94b681
commit 395875edb7
4 changed files with 35 additions and 452 deletions

View File

@ -1,89 +0,0 @@
module Data.Tree where
import Prelude
import Control.Comonad.Cofree (Cofree, head, mkCofree, tail, (:<))
import Control.Monad.Rec.Class (Step(..), tailRec)
import Data.Array (snoc, uncons)
import Data.Maybe (Maybe(..))
import Data.Monoid (power)
import Data.Traversable (Accum)
-- | A Rose, or multi-way tree, with values of type `a`.
type Tree a =
Cofree Array a
type Forest a =
Array (Tree a)
-- | Create a `Tree` from a `Node` value of type `a` and a `Forest` of children.
mkTree ∷ ∀ a. a -> Forest a -> Tree a
mkTree = mkCofree
mkLeaf ∷ ∀ a. a -> Tree a
mkLeaf = flip mkTree []
-- | Draw a 2D `String` representation of a `Tree String`.
drawTree ∷ Tree String -> String
drawTree t = tailRec go { level: 0, drawn: (head t) <> "\n", current: (tail t) }
where
go ∷ { current ∷ Forest String, drawn ∷ String, level ∷ Int } -> Step { current ∷ Forest String, drawn ∷ String, level ∷ Int } String
go x = case x { current = uncons x.current } of
{ drawn: s, current: Nothing } -> Done s
{ level: l, drawn: s, current: Just { head: c, tail: cs } } ->
let
drawn = (power " " l) <> "|----> " <> (head c) <> "\n"
in
Loop { level: l, drawn: s <> drawn <> (tailRec go { level: l + 1, drawn: "", current: (tail c) }), current: cs }
-- | Draw a 2D `String` representation of a `Tree` composed of `Show`able
-- | elements.
showTree ∷ ∀ a. Show a => Tree a -> String
showTree = drawTree <<< (map show)
-- | Scan a `Tree`, accumulating values of `b` there are constant across `Node`s
-- | that have the same parent.
scanTree ∷ ∀ a b. (a -> b -> b) -> b -> Tree a -> Tree b
scanTree f b n =
let
fb = f (head n) b
in
fb :< (tailRec go { b: fb, current: (tail n), final: [] })
where
go ∷ { final ∷ Forest b, current ∷ Forest a, b ∷ b } -> Step { final ∷ Forest b, current ∷ Forest a, b ∷ b } (Forest b)
go x = case x { current = uncons x.current } of
{ current: Nothing, final } -> Done final
{ b: b', current: Just { head: c, tail: cs }, final } ->
let
fb' = f (head c) b'
in
Loop { b: b', current: cs, final: snoc final (fb' :< tailRec go { b: fb', current: (tail c), final: [] }) }
-- | Scan a `Tree`, accumulating values of `b` there are constant across `Node`s
-- | that have the same parent, and returning a `Tree` of type `c`.
scanTreeAccum ∷ ∀ a b c. (a -> b -> Accum b c) -> b -> Tree a -> Tree c
scanTreeAccum f b n =
let
fb = f (head n) b
in
fb.value :< (tailRec go { b: fb.accum, current: (tail n), final: [] })
where
go ∷ { final ∷ Forest c, current ∷ Forest a, b ∷ b } -> Step { final ∷ Forest c, current ∷ Forest a, b ∷ b } (Forest c)
go x = case (x { current = uncons x.current }) of
{ current: Nothing, final } -> Done final
{ b: b', current: Just { head: c, tail: cs }, final } ->
let
fb' = f (head c) b'
in
Loop { b: b', current: cs, final: snoc final (fb'.value :< tailRec go { b: fb'.accum, current: (tail c), final: [] }) }
-- | Set the value of a node.
setNodeValue ∷ ∀ a. a -> Tree a -> Tree a
setNodeValue a n = a :< (tail n)
-- | Modify the value of a node.
modifyNodeValue ∷ ∀ a. (a -> a) -> Tree a -> Tree a
modifyNodeValue f n = f (head n) :< tail n
-- | Append a child to a node.
appendChild ∷ ∀ a. Tree a -> Tree a -> Tree a
appendChild c n = head n :< snoc (tail n) c

View File

@ -1,333 +0,0 @@
module Data.Tree.Zipper where
import Prelude
import Control.Alt ((<|>))
import Control.Comonad.Cofree (head, tail, (:<))
import Data.Array (drop, reverse, take, uncons, (!!), (:))
import Data.Maybe (Maybe(Just, Nothing))
import Data.Tree (Forest, Tree, mkTree, modifyNodeValue, setNodeValue)
-- | The `Loc` type describes the location of a `Node` inside a `Tree`. For this
-- | we store the current `Node`, the sibling nodes that appear before the current
-- | node, the sibling nodes that appear after the current node, and a `Array` of
-- | `Loc`ations that store the parent node locations up to the root of the three.
-- |
-- | So, effectively, the `parents` field records the path travelled in the
-- | tree to reach the level of the current `Node` starting from the tree's root,
-- | and the `before` and `after` fields describe its location in the current
-- | level.
newtype Loc a = Loc
{ node ∷ Tree a
, before ∷ Forest a
, after ∷ Forest a
, parents ∷ Array (Loc a)
}
instance eqLoc ∷ Eq a => Eq (Loc a) where
eq (Loc r1) (Loc r2) =
(r1.node == r2.node)
&& (r1.before == r2.before)
&& (r1.after == r2.after)
&& (r1.parents == r2.parents)
-- -- Cursor movement
-- | Move the cursor to the next sibling.
next ∷ ∀ a. Loc a -> Maybe (Loc a)
next (Loc r) = case uncons r.after of
Nothing -> Nothing
Just { head: c, tail: cs } ->
Just
$ Loc
{ node: c
, before: r.node : r.before
, after: cs
, parents: r.parents
}
-- -- | Move the cursor to the previous sibling.
prev ∷ ∀ a. Loc a -> Maybe (Loc a)
prev (Loc r) = case uncons r.before of
Nothing -> Nothing
Just { head: c, tail: cs } ->
Just
$ Loc
{ node: c
, before: cs
, after: r.node : r.after
, parents: r.parents
}
-- -- | Move the cursor to the first sibling.
first ∷ ∀ a. Loc a -> Loc a
first l@(Loc r) = case uncons r.before of
Nothing -> l
Just { head: c, tail: cs } ->
Loc
$
{ node: c
, before: []
, after: (reverse cs) <> r.after
, parents: r.parents
}
-- -- | Move the cursor to the last sibling.
last ∷ ∀ a. Loc a -> Loc a
last l@(Loc r) = case uncons (reverse r.after) of
Nothing -> l
Just { head: c, tail: cs } ->
Loc
$
{ node: c
, before: cs <> r.before
, after: []
, parents: r.parents
}
-- -- | Move the cursor to the parent `Node`.
up ∷ ∀ a. Loc a -> Maybe (Loc a)
up l@(Loc r) = case uncons r.parents of
Nothing -> Nothing
Just { head: p, tail: ps } ->
Just
$ Loc
{ node: (value p) :< (siblings l)
, before: before p
, after: after p
, parents: ps
}
-- | Move the cursor to the root of the tree.
root ∷ ∀ a. Loc a -> Loc a
root l = case up l of
Nothing -> l
Just p -> root p
-- | Move the cursor to the first child of the current `Node`.
firstChild ∷ ∀ a. Loc a -> Maybe (Loc a)
firstChild n = case uncons (children n) of
Nothing -> Nothing
Just { head: c, tail: cs } ->
Just
$ Loc
{ node: c
, before: []
, after: cs
, parents: n : (parents n)
}
-- | Move the cursor to the first child of the current `Node`.
down ∷ ∀ a. Loc a -> Maybe (Loc a)
down = firstChild
-- | Move the cursor to the last child of the current `Node`.
lastChild ∷ ∀ a. Loc a -> Maybe (Loc a)
lastChild p = last <$> down p
-- | Move the cursor to a specific sibling by it's index.
siblingAt ∷ ∀ a. Int -> Loc a -> Maybe (Loc a)
siblingAt i l@(Loc r) = case up l of
Nothing -> Nothing
Just p -> case (children p) !! i of
Nothing -> Nothing
Just c ->
let
before' = reverse $ take i (children p)
after' = drop (i + 1) (children p)
in
Just
$ Loc
{ node: c
, before: before'
, after: after'
, parents: r.parents
}
-- | Move the cursor to a specific child of the current `Node` by it's index.
childAt ∷ ∀ a. Int -> Loc a -> Maybe (Loc a)
childAt i p = (firstChild p) >>= (siblingAt i)
-- | Retrieve the `Tree` representation, i.e., returns the root `Node` of the
-- | current tree.
toTree ∷ ∀ a. Loc a -> Tree a
toTree = node <<< root
-- | Get a `Loc`ation representation from a given `Tree`.
fromTree ∷ ∀ a. Tree a -> Loc a
fromTree n =
Loc
{ node: n
, before: []
, after: []
, parents: []
}
-- | Set the `Node` at the current position.
setNode ∷ ∀ a. Tree a -> Loc a -> Loc a
setNode a (Loc r) =
Loc
{ node: a
, before: r.before
, after: r.after
, parents: r.parents
}
-- | Set the `Node` at the current position.
modifyNode ∷ ∀ a. (Tree a -> Tree a) -> Loc a -> Loc a
modifyNode f (Loc r) =
Loc
{ node: f r.node
, before: r.before
, after: r.after
, parents: r.parents
}
-- | Set the value of the current `Node`.
setValue ∷ ∀ a. a -> Loc a -> Loc a
setValue a l = setNode (setNodeValue a (node l)) l
-- | Modify the value of the current `Node`.
modifyValue ∷ ∀ a. (a -> a) -> Loc a -> Loc a
modifyValue f l = setNode (modifyNodeValue f (node l)) l
-- -- insert and delete nodes
-- | Insert a node after the current position, and move cursor to the new node.
insertAfter ∷ ∀ a. Tree a -> Loc a -> Loc a
insertAfter n l =
Loc
{ node: n
, after: after l
, before: (node l) : (before l)
, parents: parents l
}
-- | Insert a node before the current position, and move cursor to the new node.
insertBefore ∷ ∀ a. Tree a -> Loc a -> Loc a
insertBefore n l =
Loc
{ node: n
, after: (node l) : (after l)
, before: before l
, parents: parents l
}
-- | Insert a node as a child to the current node, and move cursor to the new node.
insertChild ∷ ∀ a. Tree a -> Loc a -> Loc a
insertChild n l = case down l of
Just c -> insertAfter n c
Nothing ->
Loc
{ node: n
, after: []
, before: []
, parents: l : (parents l)
}
-- | Delete the node in the current position.
delete ∷ ∀ a. Loc a -> Loc a
delete l@(Loc r) = case uncons r.after of
Just { head: c, tail: cs } ->
Loc
{ node: c
, before: r.before
, after: cs
, parents: r.parents
}
Nothing -> case uncons r.before of
Just { head: c, tail: cs } ->
Loc
{ node: c
, before: cs
, after: r.after
, parents: r.parents
}
Nothing -> case uncons r.parents of
Nothing -> l
Just { head: c } ->
Loc
{ node: mkTree (value c) []
, before: before c
, after: after c
, parents: parents c
}
-- Searches
-- | Search down and to the right for the first occurence where the given predicate is true and return the Loc
findDownWhere ∷ ∀ a. (a -> Boolean) -> Loc a -> Maybe (Loc a)
findDownWhere predicate loc
| predicate $ value loc = Just loc
findDownWhere predicate loc = lookNext <|> lookDown
where
lookNext = next loc >>= findDownWhere predicate
lookDown = down loc >>= findDownWhere predicate
-- | Search for the first occurence of the value `a` downwards and to the right.
findDown ∷ ∀ a. Eq a => a -> Loc a -> Maybe (Loc a)
findDown a = findDownWhere (_ == a)
-- | Search to the left and up for the first occurence where the given predicate is true and return the Loc
findUpWhere ∷ ∀ a. (a -> Boolean) -> Loc a -> Maybe (Loc a)
findUpWhere predicate loc
| predicate $ value loc = Just loc
findUpWhere predicate loc = lookPrev <|> lookUp
where
lookPrev = prev loc >>= findUpWhere predicate
lookUp = up loc >>= findUpWhere predicate
-- | Search for the first occurence of the value `a` upwards and to the left,
findUp ∷ ∀ a. Eq a => a -> Loc a -> Maybe (Loc a)
findUp a = findUpWhere (_ == a)
-- | Search from the root of the mkTree for the first occurrence where the given predicate is truen and return the Loc
findFromRootWhere ∷ ∀ a. (a -> Boolean) -> Loc a -> Maybe (Loc a)
findFromRootWhere predicate loc
| predicate $ value loc = Just loc
findFromRootWhere predicate loc = findDownWhere predicate $ root loc
-- | Search for the first occurence of the value `a` starting from the root of
-- | the tree.
findFromRoot ∷ ∀ a. Eq a => a -> Loc a -> Maybe (Loc a)
findFromRoot a = findFromRootWhere (_ == a)
-- | flattens the Tree into a Array depth first.
flattenLocDepthFirst ∷ ∀ a. Loc a -> Array (Loc a)
flattenLocDepthFirst loc = loc : (go loc)
where
go ∷ Loc a -> Array (Loc a)
go loc' =
let
downs = goDir loc' down
nexts = goDir loc' next
in
downs <> nexts
goDir ∷ Loc a -> (Loc a -> Maybe (Loc a)) -> Array (Loc a)
goDir loc' dirFn = case (dirFn loc') of
Just l -> l : go l
Nothing -> []
-- Setters and Getters
node ∷ ∀ a. Loc a -> Tree a
node (Loc r) = r.node
value ∷ ∀ a. Loc a -> a
value = head <<< node
before ∷ ∀ a. Loc a -> Forest a
before (Loc r) = r.before
after ∷ ∀ a. Loc a -> Forest a
after (Loc r) = r.after
parents ∷ ∀ a. Loc a -> Array (Loc a)
parents (Loc r) = r.parents
children ∷ ∀ a. Loc a -> Forest a
children = tail <<< node
siblings ∷ ∀ a. Loc a -> Forest a
siblings (Loc r) = (reverse r.before) <> (r.node : r.after)

View File

@ -7,7 +7,7 @@ import Data.Foldable (fold)
import Data.Tuple.Nested ((/\))
import Data.Monoid (power)
import Data.Traversable (traverse)
import Data.Tree (Forest, Tree, mkLeaf, mkTree)
import Yoga.Tree (Forest, Tree, mkLeaf, mkTree)
import Effect (Effect)
import Effect.Unsafe (unsafePerformEffect)
import React.Basic (JSX, element, fragment)
@ -19,19 +19,19 @@ import Yoga.Block.Container.Style as Styles
import Yoga.Block.Internal (createRef)
import Yoga.Block.Molecule.TableOfContents as TableOfContents
default
{ decorators ∷ Array (Effect JSX -> JSX)
, title ∷ String
}
default
{ decorators ∷ Array (Effect JSX -> JSX)
, title ∷ String
}
default =
{ title: "Molecule/TableOfContents"
, decorators:
[ \storyFn ->
R.div_
[ element E.global { styles: Styles.global }
, unsafePerformEffect storyFn
]
]
[ \storyFn ->
R.div_
[ element E.global { styles: Styles.global }
, unsafePerformEffect storyFn
]
]
}
tableOfContents ∷ Effect JSX
@ -83,6 +83,7 @@ tableOfContents = do
_ -> R.h4'
(fragment [ heading </ { ref } /> [ R.text label ], blabla depth ])
<> foldMap (go (depth + 1)) children
content ∷ Array JSX
content = tocData <#> treeToHeading
toc <> fold content

View File

@ -5,7 +5,7 @@ module Yoga.Block.Molecule.TableOfContents.View
, PropsF
) where
import Data.Tree (Forest)
import Yoga.Tree (Forest)
import React.Basic.DOM (css)
import React.Basic.DOM as R
import Yoga.Block.Container.Style (colour)
@ -39,26 +39,30 @@ rawComponent =
\(_ ∷ { | PropsOptional }) ref -> React.do
pure do
R.div'
</ { style:
css
{ position: "fixed"
, background: colour.backgroundLayer2
, padding: 0
, margin: 0
}
</
{ style:
css
{ position: "fixed"
, background: colour.backgroundLayer2
, padding: 0
, margin: 0
}
, ref
}
/> [ R.div'
</ { style:
css
{ display: "flex"
, flexDirection: "row"
, alignItems: "stretch"
, justifyContent: "flex-start"
, padding: 0
, margin: 0
}
/>
[ R.div'
</
{ style:
css
{ display: "flex"
, flexDirection: "row"
, alignItems: "stretch"
, justifyContent: "flex-start"
, padding: 0
, margin: 0
}
}
/> [ R.text "Hi"
/>
[ R.text "Hi"
]
]