<commit_before>#+startup: hidestars odd
#+TODO: TODO(t) START(s) CODE(c) | SORTA(y) DONE(d) UPSTREAM(u)

* About

  We are increasingly lost in the sea of information that surrounds us.

  So many valuable things we discover are being routinely lost.
  So many contexts that ought to, never do intersect.
  So many thoughts that could, never come.

  Why?

  Because data entry, interning and recovery is harder than it could be.

  /Holotype/ is a general-purpose mind assistant, that is an attempt to change that.

  A balanced, varied approach to resolve the conflict between extreme ease of use
  and completeness of data being captured.

  It also is supposed to try to be beautiful to the eye.

  This is a design-ish document in disarray (everything in random order),
  accompanied with some code to support it.

* State

  Nothing to speak of, yet -- mostly just ideas, with some technological
  groundwork done, like FRP & visualisation: [[https://github.com/deepfire/reflex-glfw][reflex-glfw]], and a very basic
  [[http://www.lambdacube3d.com/][LambdaCube3d]] setup for a 2.5D UI.

* Goals

  This is running in several directions at once, with the obvious caveats applicable.

  1. Map the entire resident context (headspace) available in a convenient way
  2. Facilitate context switching by introducing sub-contexts
* Ideas pipeline
*** Inspiration material
    - Self-discoverable expert cli interfaces ::
      - Felix: if you ever wondered what's the state of the art regarding self-discoverable expert cli interfaces: https://kakoune.org/ <= this editor is crazy good regarding that
    - Mendix (low-code) ::
      - http://sandervanderburg.blogspot.com/2018/06/my-introduction-to-mendix-and-low-code.html
    - ECS ::
      - conceptual intro ::
        - https://slide-rs.github.io/specs/
        - https://github.com/jonascarpay/apecs/blob/master/tutorials/RTS.md
      - apecs   :: https://github.com/jonascarpay/apecs
      - ecstasy :: http://reasonablypolymorphic.com/blog/why-take-ecstasy
    - http://graphdrawing.org/
      - 2010 ::
        - doi:10.1007/978-3-642-18469-7
        - http://www.graphdrawing.org/gd2010/accepted.html
      - 2014 ::
        - doi:10.1007/978-3-662-45803-7
        -
      - 2015 :: http://www.csun.edu/gd2015/
        - doi:10.1007/978-3-319-27261-0
        - http://www.csun.edu/gd2015/accepted.htm
      - 2016 :: https://arxiv.org/html/1609.02443v1
    - http://users.encs.concordia.ca/~haarslev/publications/
    - flexbox layout implementations ::
      - https://github.com/xamarin/flex/blob/master/flex.c
        - initial re-implementation:
          - =b77ebb29d6e9c34a4d998d3eacacde50f95ba073=
          - 2017-10-24 17:35:55
          - "update document to follow recent changes"
      - https://github.com/randrew/layout/blob/master/layout.h
    -
      #+BEGIN_QUOTE
      <NAME>'s Sketchpad demo - Object oriented graphics using a constraint
      based system (https://www.youtube.com/watch?v=6orsmFndx_o)

      <NAME>'s demo - too many innovations to list, but includes real
      time collaboration (he demoed in a convention center while the system ran 30
      miles away in his lab, connected by a leased line operating at 1200
      baud!). People think he just invented the mouse, but the overarching theme in
      his work was augmenting human
      capabilities... http://dougengelbart.org/firsts/dougs-1968-demo.html
      #+END_QUOTE
***** Performance tuning
      - https://trofi.github.io/posts/193-scaling-ghc-make.html
      - https://github.com/haskell-perf/checklist
*** General random ideas
***** UI trope: simple is powerful

      1. Arrows move
         - +modifiers = ...
      2. Space pages
      3. Tab cycles state/mode
      4. Escape pops
      5. Return vs. C-Return -- a story of multi-line text input

***** UI trope: level-of-detail variance

      1. "give me more data about this object"
         1. scaling
            1. points-of-interest at low scale
         2. Alt-hold-like extension of details shown
      1. sources & foci factoring out common information from data, which is allowed
         to remain non-enriched -- which makes sources+foci be like functions
         - which leads to need for "pinning" values of those projections, for those
           values the user considered important

***** Efficient processing of data sets

      1. "well-behaved":  process large datasets efficiently (lazily, if needed)

***** Principled: mathematical semantics for querying

      1. a multiple set co-reduction/co-projection model
      2. a path language derived from above

***** Interop

      1. external application embedding (WM-like)

***** Dealing with external world / state

      1. reify *query results* as *projection* called *stage*, that is out of sync by definition

      2. be very clear about running external processes: can be very frustrating to
         not know what happens
*** Toolbox
    - versioning
      - https://github.com/lortabac/versioning
    - open sums
      - https://github.com/patrickt/fastsum/blob/master/examples/Main.hs
    - stupid & reliable distributed ACID DB:
      - https://github.com/crclark/foundationdb-haskell
*** Open questions

    - reliable ephemeral identification for tag overlays ::
         How to pin overlaid metadata to source data -- there are sources we have no
         structural (or even mutation) control over, so can't pin "within" the data.
    - model does not cover data mutability ::

***** Graph representation
******* DONE DeltaGraph

        - source :: [[http://cs.binghamton.edu/~pdexter1/icfp-haskell2016-paper22.pdf][2016 <NAME> - Lazy Graph Processing in Haskell]]
        - conclusion :: not ready for consumption, according to authors

******* DONE data-reify

        - source :: [[http://www.ittc.ku.edu/~andygill/papers/reifyGraph.pdf][2009 Gill - Type-Safe Observable Sharing in Haskell]]
        - conclusion :: specific tool for discharging direct object references

******* SORTA Huet’s Zipper

        - source :: [[http://www.cs.tufts.edu/~nr/pubs/zipcfg.pdf][2005 <NAME> - An Applicative Control-Flow Graph Based on Huet’s Zipper]]
        - source :: [[http://www.cs.tufts.edu/~nr/pubs/hoopl10.pdf][2010 <NAME> - Hoopl: A Modular, Reusable Library for Dataflow Analysis and Transformation]]
        - key properties ::
          - unclear improvement over simpler encoding

******* SORTA Lazy I/O and graphs: Winterfell to King's Landing

        - source :: https://jaspervdj.be/posts/2017-01-17-lazy-io-graphs.html
        - key properties ::
          - =unsafeInterleaveIO=-driven SQL peeking
          - direct object references

******* TODO The Monad Reader #5 - Practical Graph Handling

        - source :: https://wiki.haskell.org/The_Monad.Reader/Issue5/Practical_Graph_Handling
        - key properties ::

******* Current best idea

        A simple map of node ids to nodes.

***** Interactive development
******* START halive

        - [ ] fix https://github.com/lukexi/halive/issues/22

***** Data sources
******* Properties

        - type ::
          - structure
          - identification across persistence
	    - only for metadata-external types, to enable tag overlays
        - rendering ::
          - meaningful views
        - metadata externality ::
          - local to data sources
          - overlaid from specialized storage

******* Types

        - source types ::
          - by structure ::
	    - tagged sets
	    - hierarchies
	      - file system
	    - graphs
        - element types ::
          - by structure ::
            - atomic :: (point with attributes)
              - meta
              - pdf
              - media
            - complex ::
              - outlines
                - org
              - graph files
                - graphml
                  - yEd graphml: find definition for https://github.com/tuura/pangraph/issues/7#issuecomment-273645083
                - vue

***** Storage backends
      - should support rich (schema-capable, version-capable) semantics
***** Scene composition
******* Phases, quick overview

        - Select                             :: filter stores through =Selector=, yield =Selection=
        - Choose presenting engine           :: emphasize user agency, deemphasize static rules like defaulting
          - context?
        - Visibility constraint computation  :: engine decides on how much can be shown
        - Viewport positioning               :: engine decides how to place the view around focus
        - Viewport culling                   :: engine decides on what elements fit into the chosen view
        - Layout                             :: obtain what is already covered, cover what isn't, compose;  compute scene modifiers
        - Render                             :: ...

******* Functions, quick overview

        - select         :: Structure struc ⇒      Source → Selector struc → Selection struc
        - compute_cull   :: Presenter struc eng ⇒  eng → (Granularity, MinSize) → Cull eng
        - place_viewport :: Presenter struc eng ⇒  eng → Selection struc → Focus struc → Cull eng → Viewport eng
        - cull_selection :: Presenter struc eng ⇒  eng → Selection struc → ViewArgs → Viewport eng → (View struc, Boundary eng
        - layout         :: Presenter struc eng ⇒  eng → (View struc, Boundary eng) → (Layout eng, Ephemeral eng)
        - render         :: RenderContext ren ⇒    ren → (View struc, Boundary eng) → (Layout eng, Ephemeral eng) → IO ()
        - interact       :: InputSys is ⇒          is → (View struc, Boundary eng) → Affective → Affective

******* Phases

        - Select :: Source → Selector → Selection
          - What :: select from Source
          - =Selections= split into the following categories, by structure:
            - General graph
            - DAG (directed acyclic graph)
            - Set -- with customisable ordering
              - XXX: ordering not factored in
          - Design considerations ::
            - XXX: live-updating selections
              - just carry update frequency for re-selection? (DONE)
              - any kind of policy that would be more.. reactive?
            - XXX: partial selections?
              - what for?
                - for hopelessly large data sets we can limit
                  - but a dumb cutoff isn't useful
                  - so, a smart, movable cutoff is needed
            - does it make sense for a selector to be non-specific about what it returns?
              - hard to say just yet, we need experience as guide

        - Presenter choice :: Selection → PresPref → Presenter
          - =PresPref= picks a specific =Presenter=, compatible with the current
            =Selection= structure:
            - defaults to last used
            - size limits for non-partial-capable engines?
            - can be cycled through by a shortcut
          - Engines:
            - Graph, dag, tree:
              - =SideGraph=: graph from aside
              - =DownGraph=: graph, arrow aligned weighted partitioning
            - Dag (duplicates-encoded), tree:
              - =DagList=, list entries
              - =DagGrid=, icon grid
              - =DagSpace=, space partitioning, ala /Lamdu/
            - Set:
              - =Carousel=
              - =Grid=
              - =List=
          - Summing up, *fundamentally* we want:
            1. type classes for individual LEs, because it allows for a
               seriously neat organisation of code
            2. multiple LEs associated with a structure, because that's how
               the problem domain looks
            3. #1 gives that there isn't a monotype for a LE

        - Visibility constraints computation :: Presenter → (Granularity, MinSize) → Cull
          - disconnected from specific elements -- deals with UI constraints projected onto a
            specific layout engine:
            - for SideGraph and SideDag -- no idea, let practice guide us..
            - for space partitioning it's trivial -- granularity says it all
            - for a Grid and DagGrid -- how many rows and columns
            - for a List -- how many rows
          - updated only rarely -- when the user changes the visualisation parameters

        - Viewport positioning :: Presenter → Selection → Focus → Cull → Viewport
          - How do we position a viewport?
            - If we don't have a focus, then it wouldn't make sense to have a viewport
              - Pick a "first" element (maybeHead $ fromList set, e.g.)
            - If we don't have a viewport, generate one containing the focus
            - if we do have a viewport, and the focus is inside -- choice is upon the engine
            - if we the focus is outside, shift the viewport -- how exactly is upon the engine
          - The above exposes following questions:
            - what does "inside a viewport" mean?
            - how can we generate a viewport that is guaranteed to contain a focus?
          - The answer seems to have the shape of a structure-specific visibility
            constraint specifier -- a =Cull=.

        - Viewport culling :: Presenter → Selection → (Granularity, MinSize) → Viewport → (View, Boundary)
          - XXX: what's the story about half-visible objects?
            - select all intersecting, render more than what is showable?
          - XXX: what's the story about avoidable layout recomputation?
            - *key question*: is it bad?  In case of SideGraph, which *is* about
                              total representation, it's very very bad.
            - *caseanalysis* cacheable total-cost    can-partial partial-composable
              - SideGraph:    yes       very hard     no(?)       no(?)
              - DownGraph:    no        medium-small  yes         yes
              - DagList:      yes       small         yes         yes
              - DagGrid:      yes       medium-small  yes         yes
              - DagSpace:     yes       very hard     yes         yes
              - Carousel:     no        easy          no          no
              - Grid:         yes       easy          yes         yes
              - List:         yes       easy          yes         yes
            - *option*: compute base layout, then viewportcull and localise from base
              - for huge selections this produces unnecessary computation
            - *option*: go with partials and compose them, whenever possible
              - if so, layout needs to be:
                - restartable at arbitrary point
                - splittable and composable
            - *option*: lazy evaluation?
            - NOTE: all obvious caching solutions seem to rely on *Ord*
          - =Granularity= determines, for tree layouts, the maximum depth of
            subdivision, after which abbreviation is engaged
          - =MinSize= limits the minimum element size
          - =Viewport= is specific to =Presenter=:
            - SideGraph: layout-global position
            - DownGraph: subroot node
            - DagList:   row offset
            - DagGrid:   row offset
            - DagSpace:  vertical offset (it's possible, because it's weighted space partitioning, but...?)
            - Carousel:  current selection
            - Grid:      row offset
            - List:      row offset
          - =View= is direct elements from =Selection=
          - =Boundary= is anchor points to the parts of =Selection= that fall outside the =Viewport=

        - Layout :: Presenter → (View, Boundary) → (Layout, Ephemerals)
          - XXX: =Positions= what are they?
            - scene-specific structure and interpretation?
            - if not, global or screenspace?
            - pixel-based, or [0.0..1.0]?
          - =Ephemerals= are inherently non-persistent, layout-specific things like:
            - element focus visulalisation state:
              - scale change, to indicate foreground/background

        - Change summary ::
          - What effect did the last =Selector= change have?  Not always obvious.

        - Render :: RenderContext → (View, Boundary) → (Layout, Ephemerals) → IO ()

        - Interaction :: Inputs → (View, Boundary) → Focus → (Granularity, MinSize) → Selector → PresPref → (Modifiers, Focus, (Granularity, MinSize), Selector, PresPref)
*** Concepts available for implementation
***** (To be) Displayable structures

      - Graphs ::
        - Views ::
          - Z-axis ::
            - Classic side view ::
                 Needs root detection, for automatic layout.
          - Arrow-aligned ::
            - Weighted partitioning ::

      - Dags ::
        - Views ::
          - Z-axis :: inherited from Graphs
          - Y-axis :: inherited from Graphs
          - Treeview, list entries, with duplication ::
          - Treeview, icon grid, with duplication ::
          - Treeview, space partitioning, ala Lamdu, with duplication ::
        - Subsetting ::
          - Viewport ::
                       Arrow walker -- for nodes.
                       Iterative refinement -- subsetting and context narrowing.
                       Some kind of a shortcut-based jump language.
                       Bookmarks.
          - Ellipsis ::
                       Zoomable: "everything else in this direction"
                       What cases need it, given a proper Viewport subsetter?

      - Sets ::
        - Views ::
          - Carousel ::
          - Grid ::
          - List ::
        - Subsetting ::
          - Viewport ::
                       Iterative refinement makes it useful.
                       Arrow walker -- for refinement elements and for.

          - Summary  ::
                       Extracting and exposing set structure.
          - Ellipsis ::
                       Logic summary or an explicit summary.
***** Visualisable qualities

      - Exhaustivity ::
        - Explicit "unknown" remaining
      - Variant-ness ::
        - Simultaneous
        - Per-choice filtering
      - Progression ::
      - Distinctions ::
        - Decomposition vs. dependency
* Implemented
*** Substrates
***** Flatland -- primordial soup of units of scale, color, dimension, area
      ..and associated operations
***** HoloCairo -- Flatland + Cairo-based drawing & font-work
      - fairly flexible font selection with aliases, vector/bitmap distinction, variants and defaulting
*** Components
***** Flex -- 2d Flexbox-based abstract layout engine
***** HoloPort -- manage/show abstract Visuals with identity
      - LambdaCube3D-based, so richly extensible
      - picking supported
      - 2.5D
      - screen/frame management
      - targetable by HoloCairo
***** Holo -- Reflex FRP-based composable widget layer
      - vocabulary:
        - As :: a Name that Denotes a type
        - Interp :: Interpret a type into another
        - Mutable :: evolution in response to events subscribed to
        - Holo :: build upon the above -- mix input events with others to define a
                  dynamic As/Interp-defined interactive widget
******* Considerations
        - why did we (mistakenly) go with: (As a, As b) => As (a, b)
          - originally:  -> Holo (Di a)
          - also: Denoted n ~ (a, a)
        - the mistake of (As a, As b) => As (a, b) -- necessitates own,
          intra-widget focus management, since specialised input is impossible due
          to genericity
        - let's go back to generic Holo (Di a)
          - does it need an As n, Denoted n ~ a, Interp a (Di b)?
          - What is implementable/not for a multi-Identity composite?
            - [-] As n, Denoted n ~ Composite -- necessitates a single Identity
            - [-] Mutable Composite -- we have a multitude of identities and want to
              reuse generic focus machinery
            - [X] Named Composite b
            - [X] Interp Composite b
          - prerequisite lift step doable generically via liftWRecord on (,)
        - let's turn liftWRecord into a Holo instance?
          - ..would require As
          - -> impossible?
***** SOP.Monadic -- abstract applicative+monadic operation on SOPs
      - generic: monadically recovers a datatype from the structure of a related
        datatype, with relationship treated in applicative context
      - allows us to lift single-product records into editable widgets
******* Goal & its problems: liftW = liftWRecord
        1. t & m that liftWRecord depends on are ambiguous
           1. must be somehow deduced from the Holo's head-bound vars
* Playbook
*** GHC compiler going AWOL
    - -ddump-tc-trace
    - -dcore-lint
* Open question archive
*** =flex= notes
***** Attributes
      - *width*, *height*        ∷ float         -- absolute-only?
      - *left*, *right*, *top*, *bottom*
                                 ∷ float         -- def(0), ???
      - *padding_LRTB*, *margin_LRTB*
                                 ∷ float         -- def(0)

      - *justify_content*        ∷ def(=ALIGN_START=)
      - *align_content*          ∷ def(=ALIGN_STRETCH=)
      - *align_items*            ∷ def(=ALIGN_START=)
      - *align_self*             ∷ def(=ALIGN_AUTO=)
      - *position*               ∷ def(=POSITION_RELATIVE=)
      - *direction*              ∷ def(=DIRECTION_COLUMN=)
      - *wrap*                   ∷ def(=NO_WRAP=)

      - *grow*                   ∷ def(0)
      - *shrink*                 ∷ def(1)
      - *order*                  ∷ def(0)
      - *basis*                  ∷ def(0)
***** =flex_item=
      - …attributes (see above)  ∷ xxx
      - *frame*                  ∷ float[4]
      - *parent*                 ∷ ptr flex_item
      - *children*               ∷ [ptr flex_item]
      - *should_order_children*  ∷ bool
***** =flex_layout=
      - set during init
        - wrap                   ∷ bool
        - reverse                ∷ bool   -- whether main axis is reversed
        - reverse2               ∷ bool   -- whether cross axis is reversed (wrap only)
        - vertical               ∷ bool
        - size_dim               ∷ float  -- main axis parent size
        - align_dim              ∷ float  -- cross axis parent size
        - frame_pos_i            ∷ uint   -- main axis position
        - frame_pos2_i           ∷ uint   -- cross axis position
        - frame_size_i           ∷ uint   -- main axis size
        - frame_size2_i          ∷ uint   -- cross axis size
        - ordered_indices        ∷ [int]

      - set for each line layout
        - line_dim               ∷ float  -- the cross-axis size
        - flex_dim               ∷ float  -- the flexible part of the main axis size
        - flex_grows             ∷ int
        - flex_shrinks           ∷ int
        - pos2                   ∷ float  -- cross axis position
        - lines                  ∷ [struct flex_layout_line]
          - child_begin          ∷ uint
          - child_end            ∷ uint
          - size                 ∷ float
        - lines_count            ∷ uint
        - lines_sizes            ∷ float
***** Function index
      - update_should_order_children() ∷ set parent's should_order_children to *true*
      - item_property_changed(property) ∷ property ≡ order → update_should_order_children
      - flex_item_new/free() ∷ malloc + default attributes & stuff / free() children, then self

*******
        - grow_if_needed                         ∷ flex_item → void
        - child_set                              ∷ flex_item → flex_item → int → void
        - flex_item_add                          ∷ flex_item → flex_item → void
        - flex_item_insert                       ∷ flex_item → void
        - flex_item_delete                       ∷ flex_item → flex_item
        - flex_item_count                        ∷ flex_item → uint
        - flex_item_child                        ∷ flex_item → flex_item
        - flex_item_parent                       ∷ flex_item → flex_item
        - flex_item_root                         ∷ flex_item → flex_item
        - flex_item_get_frame_{x,y,width,height} ∷ flex_item → float
*******
        - layout_init                            ∷ flex_item → float → float → flex_layout → void
          let width/height        = args.w/args.h - item→padding_left - item→padding_right
              (,,,,)
                reverse vertical
                size_dim align_dim
                frame_pos{,2}_i
                frame_size{,2}_i
                                  = case item→direction of
                                      DIRECTION_ROW_REVERSE    | f width height
                                      DIRECTION_ROW            |
                                      DIRECTION_COLUMN_REVERSE |
                                      DIRECTION_COLUMN         |
              ordered_indices     = | f item→should_order_children
                                    |   item→children_count
                                    |   item→children
                                    | -- sorted children indices by their =.order= property
              flex_{dim,grows,shrinks}
                                  = (,,) 0 0 0
              wrap                = item→wrap != NO_WRAP
              (,) pos2 reverse2   = | f wrap item→wrap
                                    |   align_dim
                                    |   vertical
                                    |   item→padding_top
              lines               = []
          in Layout{..}
        - layout_cleanup                         ∷ flex_layout → void
*******
        - LAYOUT_RESET                           ∷ flex_layout → flex_layout
          layout & line_dim     .~ if wrap then 0 else align_dim
                 & flex_dim     .~ size_dim
                 & flex_grows   .~ 0
                 & flex_shrinks .~ 0
        - _LAYOUT_FRAME                          ∷ layout → child → {pos,pos2,size,size2} → float
        - CHILD_POS, CHILD_POS2, CHILD_SIZE, CHILD_SIZE2 = _LAYOUT_FRAME(…)
        - CHILD_MARGIN                           ∷ child → if_vertical ∷ bool → if_horizontal ∷ bool →
*******
        - layout_align                           ∷ align           ∷ flex_align →
                                                   flex_dim        ∷ float →
                                                   children_count  ∷ uint →
                                                   pos_p           ∷ ptr float →
                                                   spacing_p       ∷ ptr float →
                                                   stretch_allowed ∷ bool

        - child_align                            ∷ child ∷ flex_item → parent ∷ flex_item → flex_align

        - layout_items                           ∷ item            ∷ flex_item →
                                                   child_begin     ∷ uint →
                                                   child_end       ∷ uint →
                                                   children_count  ∷ int →
                                                   layout          ∷ flex_layout → void

        - layout_item                            ∷ item            ∷ flex_item →
                                                   width           ∷ float →
                                                   height          ∷ float

        - flex_layout                            ∷ item            ∷ flex_item → void
***** Algorithm
*** Layout data flow summary

    Note: this leaves view-porting (as an overflow handling mechanism) out of scope for now.

***** Possibilities

      | Leaf  | Modifier  | FromTop | Style         | Hardness | ToTop | Shrink method | Notes                                     |
      |-------+-----------+---------+---------------+----------+-------+---------------+-------------------------------------------|
      | Text  | One-line  | ()      | font, unbreak | Hard     | Abs   | no            |                                           |
      |       |           | ()      | font, unbreak | Soft     | Rel   | ellipsis      |                                           |
      |       | Breakable | AbsCstr | font          | Soft     | Rel   | ellipsis      | hard breakable is ⊥                       |
      | Image | Fixed     | ()      | fixed         | Hard     | Abs   | no            | soft fixed image is ⊥, unless viewporting |
      |       | Scalable  | AbsCstr | ()            | Soft     | Rel   | scale         |                                           |
      | ???   |           |         |               |          |       |               | any other leaf types?                     |

      | Inter | Modifier | FromTop | Style     | FromBot | ToBot | Hardness Honoring | ToTop |   | Notes |
      |-------+----------+---------+-----------+---------+-------+-------------------+-------+---+-------|
      | Box   |          | AbsCstr | ()        | Abs/Rel | ?     | Rebalancing       |       |   |       |
      | Wrap  |          | AbsCstr | thickness | Abs/Rel | ?     | ????????????????? |       |   |       |

      Apparent fallout from fundamentals ∷
        1. Hard requirements are naturally context-free
        2. Relative hards are possible, though (ratios being a question of design)
        3. Context-ful requirements are impossible up-front, in a single pass

      Observations ∷
        1. Child ratio knowledge is minimum for Box's downward propagation of AbsCstr
        2. Some children don't have ratios, but absolutes can be relativised
           (absolutisation of relatives is a feasible dual that can lead to better pixel-level stability)
        3. #1 + #2 → child ratios always available, and always immediately -- assuming no inter-level balancing

      Box hardness honoring procedure ∷
        1. Query all children for direct requirements
        2. Allocate hards (absolutising relatives), computing the remaining soft share
        3. Relativise all soft absolutes from #1
        4. When softs sum to overflow, normalise them
        5. When softs sum to underflow, normalise them, unless there are filler children
        6. Absolutise softs back
        7. When there's underflow and fillers, distrubute slack between fillers
        8. ??? hards overflow handling policy
           - ideally, propagate upward
             - as a "lacks absolute N"?

        Summary: hards first, then redistribute remainder while keeping fillers in mind.

      Wrap hardness honoring procedure ∷
        1. Query children for direct requirements
        2. Absolutes that fit exactly: easy
        3. Absolutes that underflow: ???
        4. Absolutes that overflow:
           - ideally, propagate upward (see same for box hardness)
* Problems
*** Node finalisation needs the internal type
***** Potential solution
      1. Make Item sport the content type by default, only wrapping it for children.
      2. Bonus: make Item into an HList-like structure!
         - that has a risk of making refactoring super-painful in the current
           prototyping phase, though.
*** DONE (m :.: Result t) a ⇒ Applicative on 'Result t' ⇒ Node construction unbearably pure
***** The problematic pipeline
      1. ct = (!! choice) $ SOP.apInjs_POP pop   ∷ SOP (m :.: Result t) xss
      2. By hsequence ∷ (SListIN h xs, SListIN (Prod h) xs, HSequence h, Applicative f) =>
          h f xs -> f (h I xs)
      3. Comp msop = hsequence ct                ∷     (m :.: Result t) (SOP I xss)
      4. By unComp ∷
          (f :.: g) p -> f (g p)
      5. msop                                    ∷      m    (Result t  (SOP I xss))
      6. By (SOP.to <$>) <$>
          m (Result t (SOP I (x : xs))) -> m (Result t a)
      7. Comp res = (SOP.to <$>) <$> msop        ∷     (m :.: Result t) a
      8. By unComp ∷
          (f :.: g) p -> f (g p)
      9. res                                     ∷      m    (Result t a)
***** Potential `hsequence` replacements
      - hsequence' ∷ (SListIN h xs, Applicative f) ⇒ h (f :.: g) xs → f (h g xs)
        hsequence  ∷                                 h  f        xs → f (h I xs)
        htraverse' ∷ (SListI2 xss, Applicative g) =>
                     (forall a ⇒ f a → g (f' a)) → SOP f xss → g (SOP f' xss)
      - g ~ m, f' ~ Result t
        -            (forall a ⇒ f a → m (Result t a)) → SOP f xss → m (SOP (Result t) xss)
***** The problematic foundation of the pipeline
      1. forall f xs. (c a, All c xs, All2 c xss)
         ⇒ …
         → (a → f)
         → (m :.: Result t) f
      2. We want to separate (Result t f) from f
      3. Theory: can we go for this instead:
         → m (Result t f)
      4. Let's try!
***** Solution
      - introduce a separate node finalisation post-phase, that performs monadic
        computation after the ADT lift
*** GHC-8.8
    - cabal-doctest
      - [X] fetchpatch
    - cabal-install
      - [X] bump for Cabal
    - generic-deriving
      - [X] bump for TH
    - data-default
      - [ ] ???
        - ["cp", "-f", "/nix/store/baa1q5ph9w2daw63vdblldq4wc5g74c0-data-default-class-0.1.2.0/lib/ghc-8.7.20190115/package.conf.d/data-default-class-0.1.2.0-FeIQ5tLoVZBHMSgrT9zptQ.conf", "/build/package.conf.d/"]
        - ["cp", "-f", "/build/package.conf.d/"]
    - haskell-src-exts
      - [ ] sigsegv in Haddock
    - gtk2hs-buildtools
      - [ ] MonadFail https://github.com/gtk2hs/gtk2hs/issues/264
    - th-lift
      - [ ] TH https://github.com/mboes/th-lift/issues/38
    - generics-sop
      - [ ] TH https://github.com/well-typed/generics-sop/issues/96
* emacs options

;; Local Variables:
;; eval: (setf indent-tabs-mode nil org-todo-keyword-faces '(("TODO" . "#6c71c4") ("START" . "#2aa198") ("CODE" . "#6c71c4") ("SORTA" . "#268bd2") ("DONE" . "#073642") ("UPSTREAM" . "#268bd2")))
;; End:
<commit_msg>README: Structure-derived UI, with triple-store-based ontologies<commit_after>#+startup: hidestars odd
#+TODO: TODO(t) START(s) CODE(c) | SORTA(y) DONE(d) UPSTREAM(u)

* About

  We are increasingly lost in the sea of information that surrounds us.

  So many valuable things we discover are being routinely lost.
  So many contexts that ought to, never do intersect.
  So many thoughts that could, never come.

  Why?

  Because data entry, interning and recovery is harder than it could be.

  /Holotype/ is a general-purpose mind assistant, that is an attempt to change that.

  A balanced, varied approach to resolve the conflict between extreme ease of use
  and completeness of data being captured.

  It also is supposed to try to be beautiful to the eye.

  This is a design-ish document in disarray (everything in random order),
  accompanied with some code to support it.

* State

  Nothing to speak of, yet -- mostly just ideas, with some technological
  groundwork done, like FRP & visualisation: [[https://github.com/deepfire/reflex-glfw][reflex-glfw]], and a very basic
  [[http://www.lambdacube3d.com/][LambdaCube3d]] setup for a 2.5D UI.

* Goals

  This is running in several directions at once, with the obvious caveats applicable.

  1. Map the entire resident context (headspace) available in a convenient way
  2. Facilitate context switching by introducing sub-contexts
* Ideas pipeline
*** Inspiration material
    - Structure-derived UI, with triple-store-based ontologies ::
      - Felix: Stumbled upon https://github.com/AshleyYakeley/Truth, made me think of you and holotype.
    - Self-discoverable expert cli interfaces ::
      - Felix: if you ever wondered what's the state of the art regarding self-discoverable expert cli interfaces: https://kakoune.org/ <= this editor is crazy good regarding that
    - Mendix (low-code) ::
      - http://sandervanderburg.blogspot.com/2018/06/my-introduction-to-mendix-and-low-code.html
    - ECS ::
      - conceptual intro ::
        - https://slide-rs.github.io/specs/
        - https://github.com/jonascarpay/apecs/blob/master/tutorials/RTS.md
      - apecs   :: https://github.com/jonascarpay/apecs
      - ecstasy :: http://reasonablypolymorphic.com/blog/why-take-ecstasy
    - http://graphdrawing.org/
      - 2010 ::
        - doi:10.1007/978-3-642-18469-7
        - http://www.graphdrawing.org/gd2010/accepted.html
      - 2014 ::
        - doi:10.1007/978-3-662-45803-7
        -
      - 2015 :: http://www.csun.edu/gd2015/
        - doi:10.1007/978-3-319-27261-0
        - http://www.csun.edu/gd2015/accepted.htm
      - 2016 :: https://arxiv.org/html/1609.02443v1
    - http://users.encs.concordia.ca/~haarslev/publications/
    - flexbox layout implementations ::
      - https://github.com/xamarin/flex/blob/master/flex.c
        - initial re-implementation:
          - =b77ebb29d6e9c34a4d998d3eacacde50f95ba073=
          - 2017-10-24 17:35:55
          - "update document to follow recent changes"
      - https://github.com/randrew/layout/blob/master/layout.h
    -
      #+BEGIN_QUOTE
      <NAME>'s Sketchpad demo - Object oriented graphics using a constraint
      based system (https://www.youtube.com/watch?v=6orsmFndx_o)

      <NAME>'s demo - too many innovations to list, but includes real
      time collaboration (he demoed in a convention center while the system ran 30
      miles away in his lab, connected by a leased line operating at 1200
      baud!). People think he just invented the mouse, but the overarching theme in
      his work was augmenting human
      capabilities... http://dougengelbart.org/firsts/dougs-1968-demo.html
      #+END_QUOTE
***** Performance tuning
      - https://trofi.github.io/posts/193-scaling-ghc-make.html
      - https://github.com/haskell-perf/checklist
*** General random ideas
***** UI trope: simple is powerful

      1. Arrows move
         - +modifiers = ...
      2. Space pages
      3. Tab cycles state/mode
      4. Escape pops
      5. Return vs. C-Return -- a story of multi-line text input

***** UI trope: level-of-detail variance

      1. "give me more data about this object"
         1. scaling
            1. points-of-interest at low scale
         2. Alt-hold-like extension of details shown
      1. sources & foci factoring out common information from data, which is allowed
         to remain non-enriched -- which makes sources+foci be like functions
         - which leads to need for "pinning" values of those projections, for those
           values the user considered important

***** Efficient processing of data sets

      1. "well-behaved":  process large datasets efficiently (lazily, if needed)

***** Principled: mathematical semantics for querying

      1. a multiple set co-reduction/co-projection model
      2. a path language derived from above

***** Interop

      1. external application embedding (WM-like)

***** Dealing with external world / state

      1. reify *query results* as *projection* called *stage*, that is out of sync by definition

      2. be very clear about running external processes: can be very frustrating to
         not know what happens
*** Toolbox
    - versioning
      - https://github.com/lortabac/versioning
    - open sums
      - https://github.com/patrickt/fastsum/blob/master/examples/Main.hs
    - stupid & reliable distributed ACID DB:
      - https://github.com/crclark/foundationdb-haskell
*** Open questions

    - reliable ephemeral identification for tag overlays ::
         How to pin overlaid metadata to source data -- there are sources we have no
         structural (or even mutation) control over, so can't pin "within" the data.
    - model does not cover data mutability ::

***** Graph representation
******* DONE DeltaGraph

        - source :: [[http://cs.binghamton.edu/~pdexter1/icfp-haskell2016-paper22.pdf][2016 <NAME> - Lazy Graph Processing in Haskell]]
        - conclusion :: not ready for consumption, according to authors

******* DONE data-reify

        - source :: [[http://www.ittc.ku.edu/~andygill/papers/reifyGraph.pdf][2009 Gill - Type-Safe Observable Sharing in Haskell]]
        - conclusion :: specific tool for discharging direct object references

******* SORTA Huet’s Zipper

        - source :: [[http://www.cs.tufts.edu/~nr/pubs/zipcfg.pdf][2005 <NAME> - An Applicative Control-Flow Graph Based on Huet’s Zipper]]
        - source :: [[http://www.cs.tufts.edu/~nr/pubs/hoopl10.pdf][2010 <NAME> - Hoopl: A Modular, Reusable Library for Dataflow Analysis and Transformation]]
        - key properties ::
          - unclear improvement over simpler encoding

******* SORTA Lazy I/O and graphs: Winterfell to King's Landing

        - source :: https://jaspervdj.be/posts/2017-01-17-lazy-io-graphs.html
        - key properties ::
          - =unsafeInterleaveIO=-driven SQL peeking
          - direct object references

******* TODO The Monad Reader #5 - Practical Graph Handling

        - source :: https://wiki.haskell.org/The_Monad.Reader/Issue5/Practical_Graph_Handling
        - key properties ::

******* Current best idea

        A simple map of node ids to nodes.

***** Interactive development
******* START halive

        - [ ] fix https://github.com/lukexi/halive/issues/22

***** Data sources
******* Properties

        - type ::
          - structure
          - identification across persistence
	    - only for metadata-external types, to enable tag overlays
        - rendering ::
          - meaningful views
        - metadata externality ::
          - local to data sources
          - overlaid from specialized storage

******* Types

        - source types ::
          - by structure ::
	    - tagged sets
	    - hierarchies
	      - file system
	    - graphs
        - element types ::
          - by structure ::
            - atomic :: (point with attributes)
              - meta
              - pdf
              - media
            - complex ::
              - outlines
                - org
              - graph files
                - graphml
                  - yEd graphml: find definition for https://github.com/tuura/pangraph/issues/7#issuecomment-273645083
                - vue

***** Storage backends
      - should support rich (schema-capable, version-capable) semantics
***** Scene composition
******* Phases, quick overview

        - Select                             :: filter stores through =Selector=, yield =Selection=
        - Choose presenting engine           :: emphasize user agency, deemphasize static rules like defaulting
          - context?
        - Visibility constraint computation  :: engine decides on how much can be shown
        - Viewport positioning               :: engine decides how to place the view around focus
        - Viewport culling                   :: engine decides on what elements fit into the chosen view
        - Layout                             :: obtain what is already covered, cover what isn't, compose;  compute scene modifiers
        - Render                             :: ...

******* Functions, quick overview

        - select         :: Structure struc ⇒      Source → Selector struc → Selection struc
        - compute_cull   :: Presenter struc eng ⇒  eng → (Granularity, MinSize) → Cull eng
        - place_viewport :: Presenter struc eng ⇒  eng → Selection struc → Focus struc → Cull eng → Viewport eng
        - cull_selection :: Presenter struc eng ⇒  eng → Selection struc → ViewArgs → Viewport eng → (View struc, Boundary eng
        - layout         :: Presenter struc eng ⇒  eng → (View struc, Boundary eng) → (Layout eng, Ephemeral eng)
        - render         :: RenderContext ren ⇒    ren → (View struc, Boundary eng) → (Layout eng, Ephemeral eng) → IO ()
        - interact       :: InputSys is ⇒          is → (View struc, Boundary eng) → Affective → Affective

******* Phases

        - Select :: Source → Selector → Selection
          - What :: select from Source
          - =Selections= split into the following categories, by structure:
            - General graph
            - DAG (directed acyclic graph)
            - Set -- with customisable ordering
              - XXX: ordering not factored in
          - Design considerations ::
            - XXX: live-updating selections
              - just carry update frequency for re-selection? (DONE)
              - any kind of policy that would be more.. reactive?
            - XXX: partial selections?
              - what for?
                - for hopelessly large data sets we can limit
                  - but a dumb cutoff isn't useful
                  - so, a smart, movable cutoff is needed
            - does it make sense for a selector to be non-specific about what it returns?
              - hard to say just yet, we need experience as guide

        - Presenter choice :: Selection → PresPref → Presenter
          - =PresPref= picks a specific =Presenter=, compatible with the current
            =Selection= structure:
            - defaults to last used
            - size limits for non-partial-capable engines?
            - can be cycled through by a shortcut
          - Engines:
            - Graph, dag, tree:
              - =SideGraph=: graph from aside
              - =DownGraph=: graph, arrow aligned weighted partitioning
            - Dag (duplicates-encoded), tree:
              - =DagList=, list entries
              - =DagGrid=, icon grid
              - =DagSpace=, space partitioning, ala /Lamdu/
            - Set:
              - =Carousel=
              - =Grid=
              - =List=
          - Summing up, *fundamentally* we want:
            1. type classes for individual LEs, because it allows for a
               seriously neat organisation of code
            2. multiple LEs associated with a structure, because that's how
               the problem domain looks
            3. #1 gives that there isn't a monotype for a LE

        - Visibility constraints computation :: Presenter → (Granularity, MinSize) → Cull
          - disconnected from specific elements -- deals with UI constraints projected onto a
            specific layout engine:
            - for SideGraph and SideDag -- no idea, let practice guide us..
            - for space partitioning it's trivial -- granularity says it all
            - for a Grid and DagGrid -- how many rows and columns
            - for a List -- how many rows
          - updated only rarely -- when the user changes the visualisation parameters

        - Viewport positioning :: Presenter → Selection → Focus → Cull → Viewport
          - How do we position a viewport?
            - If we don't have a focus, then it wouldn't make sense to have a viewport
              - Pick a "first" element (maybeHead $ fromList set, e.g.)
            - If we don't have a viewport, generate one containing the focus
            - if we do have a viewport, and the focus is inside -- choice is upon the engine
            - if we the focus is outside, shift the viewport -- how exactly is upon the engine
          - The above exposes following questions:
            - what does "inside a viewport" mean?
            - how can we generate a viewport that is guaranteed to contain a focus?
          - The answer seems to have the shape of a structure-specific visibility
            constraint specifier -- a =Cull=.

        - Viewport culling :: Presenter → Selection → (Granularity, MinSize) → Viewport → (View, Boundary)
          - XXX: what's the story about half-visible objects?
            - select all intersecting, render more than what is showable?
          - XXX: what's the story about avoidable layout recomputation?
            - *key question*: is it bad?  In case of SideGraph, which *is* about
                              total representation, it's very very bad.
            - *caseanalysis* cacheable total-cost    can-partial partial-composable
              - SideGraph:    yes       very hard     no(?)       no(?)
              - DownGraph:    no        medium-small  yes         yes
              - DagList:      yes       small         yes         yes
              - DagGrid:      yes       medium-small  yes         yes
              - DagSpace:     yes       very hard     yes         yes
              - Carousel:     no        easy          no          no
              - Grid:         yes       easy          yes         yes
              - List:         yes       easy          yes         yes
            - *option*: compute base layout, then viewportcull and localise from base
              - for huge selections this produces unnecessary computation
            - *option*: go with partials and compose them, whenever possible
              - if so, layout needs to be:
                - restartable at arbitrary point
                - splittable and composable
            - *option*: lazy evaluation?
            - NOTE: all obvious caching solutions seem to rely on *Ord*
          - =Granularity= determines, for tree layouts, the maximum depth of
            subdivision, after which abbreviation is engaged
          - =MinSize= limits the minimum element size
          - =Viewport= is specific to =Presenter=:
            - SideGraph: layout-global position
            - DownGraph: subroot node
            - DagList:   row offset
            - DagGrid:   row offset
            - DagSpace:  vertical offset (it's possible, because it's weighted space partitioning, but...?)
            - Carousel:  current selection
            - Grid:      row offset
            - List:      row offset
          - =View= is direct elements from =Selection=
          - =Boundary= is anchor points to the parts of =Selection= that fall outside the =Viewport=

        - Layout :: Presenter → (View, Boundary) → (Layout, Ephemerals)
          - XXX: =Positions= what are they?
            - scene-specific structure and interpretation?
            - if not, global or screenspace?
            - pixel-based, or [0.0..1.0]?
          - =Ephemerals= are inherently non-persistent, layout-specific things like:
            - element focus visulalisation state:
              - scale change, to indicate foreground/background

        - Change summary ::
          - What effect did the last =Selector= change have?  Not always obvious.

        - Render :: RenderContext → (View, Boundary) → (Layout, Ephemerals) → IO ()

        - Interaction :: Inputs → (View, Boundary) → Focus → (Granularity, MinSize) → Selector → PresPref → (Modifiers, Focus, (Granularity, MinSize), Selector, PresPref)
*** Concepts available for implementation
***** (To be) Displayable structures

      - Graphs ::
        - Views ::
          - Z-axis ::
            - Classic side view ::
                 Needs root detection, for automatic layout.
          - Arrow-aligned ::
            - Weighted partitioning ::

      - Dags ::
        - Views ::
          - Z-axis :: inherited from Graphs
          - Y-axis :: inherited from Graphs
          - Treeview, list entries, with duplication ::
          - Treeview, icon grid, with duplication ::
          - Treeview, space partitioning, ala Lamdu, with duplication ::
        - Subsetting ::
          - Viewport ::
                       Arrow walker -- for nodes.
                       Iterative refinement -- subsetting and context narrowing.
                       Some kind of a shortcut-based jump language.
                       Bookmarks.
          - Ellipsis ::
                       Zoomable: "everything else in this direction"
                       What cases need it, given a proper Viewport subsetter?

      - Sets ::
        - Views ::
          - Carousel ::
          - Grid ::
          - List ::
        - Subsetting ::
          - Viewport ::
                       Iterative refinement makes it useful.
                       Arrow walker -- for refinement elements and for.

          - Summary  ::
                       Extracting and exposing set structure.
          - Ellipsis ::
                       Logic summary or an explicit summary.
***** Visualisable qualities

      - Exhaustivity ::
        - Explicit "unknown" remaining
      - Variant-ness ::
        - Simultaneous
        - Per-choice filtering
      - Progression ::
      - Distinctions ::
        - Decomposition vs. dependency
* Implemented
*** Substrates
***** Flatland -- primordial soup of units of scale, color, dimension, area
      ..and associated operations
***** HoloCairo -- Flatland + Cairo-based drawing & font-work
      - fairly flexible font selection with aliases, vector/bitmap distinction, variants and defaulting
*** Components
***** Flex -- 2d Flexbox-based abstract layout engine
***** HoloPort -- manage/show abstract Visuals with identity
      - LambdaCube3D-based, so richly extensible
      - picking supported
      - 2.5D
      - screen/frame management
      - targetable by HoloCairo
***** Holo -- Reflex FRP-based composable widget layer
      - vocabulary:
        - As :: a Name that Denotes a type
        - Interp :: Interpret a type into another
        - Mutable :: evolution in response to events subscribed to
        - Holo :: build upon the above -- mix input events with others to define a
                  dynamic As/Interp-defined interactive widget
******* Considerations
        - why did we (mistakenly) go with: (As a, As b) => As (a, b)
          - originally:  -> Holo (Di a)
          - also: Denoted n ~ (a, a)
        - the mistake of (As a, As b) => As (a, b) -- necessitates own,
          intra-widget focus management, since specialised input is impossible due
          to genericity
        - let's go back to generic Holo (Di a)
          - does it need an As n, Denoted n ~ a, Interp a (Di b)?
          - What is implementable/not for a multi-Identity composite?
            - [-] As n, Denoted n ~ Composite -- necessitates a single Identity
            - [-] Mutable Composite -- we have a multitude of identities and want to
              reuse generic focus machinery
            - [X] Named Composite b
            - [X] Interp Composite b
          - prerequisite lift step doable generically via liftWRecord on (,)
        - let's turn liftWRecord into a Holo instance?
          - ..would require As
          - -> impossible?
***** SOP.Monadic -- abstract applicative+monadic operation on SOPs
      - generic: monadically recovers a datatype from the structure of a related
        datatype, with relationship treated in applicative context
      - allows us to lift single-product records into editable widgets
******* Goal & its problems: liftW = liftWRecord
        1. t & m that liftWRecord depends on are ambiguous
           1. must be somehow deduced from the Holo's head-bound vars
* Playbook
*** GHC compiler going AWOL
    - -ddump-tc-trace
    - -dcore-lint
* Open question archive
*** =flex= notes
***** Attributes
      - *width*, *height*        ∷ float         -- absolute-only?
      - *left*, *right*, *top*, *bottom*
                                 ∷ float         -- def(0), ???
      - *padding_LRTB*, *margin_LRTB*
                                 ∷ float         -- def(0)

      - *justify_content*        ∷ def(=ALIGN_START=)
      - *align_content*          ∷ def(=ALIGN_STRETCH=)
      - *align_items*            ∷ def(=ALIGN_START=)
      - *align_self*             ∷ def(=ALIGN_AUTO=)
      - *position*               ∷ def(=POSITION_RELATIVE=)
      - *direction*              ∷ def(=DIRECTION_COLUMN=)
      - *wrap*                   ∷ def(=NO_WRAP=)

      - *grow*                   ∷ def(0)
      - *shrink*                 ∷ def(1)
      - *order*                  ∷ def(0)
      - *basis*                  ∷ def(0)
***** =flex_item=
      - …attributes (see above)  ∷ xxx
      - *frame*                  ∷ float[4]
      - *parent*                 ∷ ptr flex_item
      - *children*               ∷ [ptr flex_item]
      - *should_order_children*  ∷ bool
***** =flex_layout=
      - set during init
        - wrap                   ∷ bool
        - reverse                ∷ bool   -- whether main axis is reversed
        - reverse2               ∷ bool   -- whether cross axis is reversed (wrap only)
        - vertical               ∷ bool
        - size_dim               ∷ float  -- main axis parent size
        - align_dim              ∷ float  -- cross axis parent size
        - frame_pos_i            ∷ uint   -- main axis position
        - frame_pos2_i           ∷ uint   -- cross axis position
        - frame_size_i           ∷ uint   -- main axis size
        - frame_size2_i          ∷ uint   -- cross axis size
        - ordered_indices        ∷ [int]

      - set for each line layout
        - line_dim               ∷ float  -- the cross-axis size
        - flex_dim               ∷ float  -- the flexible part of the main axis size
        - flex_grows             ∷ int
        - flex_shrinks           ∷ int
        - pos2                   ∷ float  -- cross axis position
        - lines                  ∷ [struct flex_layout_line]
          - child_begin          ∷ uint
          - child_end            ∷ uint
          - size                 ∷ float
        - lines_count            ∷ uint
        - lines_sizes            ∷ float
***** Function index
      - update_should_order_children() ∷ set parent's should_order_children to *true*
      - item_property_changed(property) ∷ property ≡ order → update_should_order_children
      - flex_item_new/free() ∷ malloc + default attributes & stuff / free() children, then self

*******
        - grow_if_needed                         ∷ flex_item → void
        - child_set                              ∷ flex_item → flex_item → int → void
        - flex_item_add                          ∷ flex_item → flex_item → void
        - flex_item_insert                       ∷ flex_item → void
        - flex_item_delete                       ∷ flex_item → flex_item
        - flex_item_count                        ∷ flex_item → uint
        - flex_item_child                        ∷ flex_item → flex_item
        - flex_item_parent                       ∷ flex_item → flex_item
        - flex_item_root                         ∷ flex_item → flex_item
        - flex_item_get_frame_{x,y,width,height} ∷ flex_item → float
*******
        - layout_init                            ∷ flex_item → float → float → flex_layout → void
          let width/height        = args.w/args.h - item→padding_left - item→padding_right
              (,,,,)
                reverse vertical
                size_dim align_dim
                frame_pos{,2}_i
                frame_size{,2}_i
                                  = case item→direction of
                                      DIRECTION_ROW_REVERSE    | f width height
                                      DIRECTION_ROW            |
                                      DIRECTION_COLUMN_REVERSE |
                                      DIRECTION_COLUMN         |
              ordered_indices     = | f item→should_order_children
                                    |   item→children_count
                                    |   item→children
                                    | -- sorted children indices by their =.order= property
              flex_{dim,grows,shrinks}
                                  = (,,) 0 0 0
              wrap                = item→wrap != NO_WRAP
              (,) pos2 reverse2   = | f wrap item→wrap
                                    |   align_dim
                                    |   vertical
                                    |   item→padding_top
              lines               = []
          in Layout{..}
        - layout_cleanup                         ∷ flex_layout → void
*******
        - LAYOUT_RESET                           ∷ flex_layout → flex_layout
          layout & line_dim     .~ if wrap then 0 else align_dim
                 & flex_dim     .~ size_dim
                 & flex_grows   .~ 0
                 & flex_shrinks .~ 0
        - _LAYOUT_FRAME                          ∷ layout → child → {pos,pos2,size,size2} → float
        - CHILD_POS, CHILD_POS2, CHILD_SIZE, CHILD_SIZE2 = _LAYOUT_FRAME(…)
        - CHILD_MARGIN                           ∷ child → if_vertical ∷ bool → if_horizontal ∷ bool →
*******
        - layout_align                           ∷ align           ∷ flex_align →
                                                   flex_dim        ∷ float →
                                                   children_count  ∷ uint →
                                                   pos_p           ∷ ptr float →
                                                   spacing_p       ∷ ptr float →
                                                   stretch_allowed ∷ bool

        - child_align                            ∷ child ∷ flex_item → parent ∷ flex_item → flex_align

        - layout_items                           ∷ item            ∷ flex_item →
                                                   child_begin     ∷ uint →
                                                   child_end       ∷ uint →
                                                   children_count  ∷ int →
                                                   layout          ∷ flex_layout → void

        - layout_item                            ∷ item            ∷ flex_item →
                                                   width           ∷ float →
                                                   height          ∷ float

        - flex_layout                            ∷ item            ∷ flex_item → void
***** Algorithm
*** Layout data flow summary

    Note: this leaves view-porting (as an overflow handling mechanism) out of scope for now.

***** Possibilities

      | Leaf  | Modifier  | FromTop | Style         | Hardness | ToTop | Shrink method | Notes                                     |
      |-------+-----------+---------+---------------+----------+-------+---------------+-------------------------------------------|
      | Text  | One-line  | ()      | font, unbreak | Hard     | Abs   | no            |                                           |
      |       |           | ()      | font, unbreak | Soft     | Rel   | ellipsis      |                                           |
      |       | Breakable | AbsCstr | font          | Soft     | Rel   | ellipsis      | hard breakable is ⊥                       |
      | Image | Fixed     | ()      | fixed         | Hard     | Abs   | no            | soft fixed image is ⊥, unless viewporting |
      |       | Scalable  | AbsCstr | ()            | Soft     | Rel   | scale         |                                           |
      | ???   |           |         |               |          |       |               | any other leaf types?                     |

      | Inter | Modifier | FromTop | Style     | FromBot | ToBot | Hardness Honoring | ToTop |   | Notes |
      |-------+----------+---------+-----------+---------+-------+-------------------+-------+---+-------|
      | Box   |          | AbsCstr | ()        | Abs/Rel | ?     | Rebalancing       |       |   |       |
      | Wrap  |          | AbsCstr | thickness | Abs/Rel | ?     | ????????????????? |       |   |       |

      Apparent fallout from fundamentals ∷
        1. Hard requirements are naturally context-free
        2. Relative hards are possible, though (ratios being a question of design)
        3. Context-ful requirements are impossible up-front, in a single pass

      Observations ∷
        1. Child ratio knowledge is minimum for Box's downward propagation of AbsCstr
        2. Some children don't have ratios, but absolutes can be relativised
           (absolutisation of relatives is a feasible dual that can lead to better pixel-level stability)
        3. #1 + #2 → child ratios always available, and always immediately -- assuming no inter-level balancing

      Box hardness honoring procedure ∷
        1. Query all children for direct requirements
        2. Allocate hards (absolutising relatives), computing the remaining soft share
        3. Relativise all soft absolutes from #1
        4. When softs sum to overflow, normalise them
        5. When softs sum to underflow, normalise them, unless there are filler children
        6. Absolutise softs back
        7. When there's underflow and fillers, distrubute slack between fillers
        8. ??? hards overflow handling policy
           - ideally, propagate upward
             - as a "lacks absolute N"?

        Summary: hards first, then redistribute remainder while keeping fillers in mind.

      Wrap hardness honoring procedure ∷
        1. Query children for direct requirements
        2. Absolutes that fit exactly: easy
        3. Absolutes that underflow: ???
        4. Absolutes that overflow:
           - ideally, propagate upward (see same for box hardness)
* Problems
*** Node finalisation needs the internal type
***** Potential solution
      1. Make Item sport the content type by default, only wrapping it for children.
      2. Bonus: make Item into an HList-like structure!
         - that has a risk of making refactoring super-painful in the current
           prototyping phase, though.
*** DONE (m :.: Result t) a ⇒ Applicative on 'Result t' ⇒ Node construction unbearably pure
***** The problematic pipeline
      1. ct = (!! choice) $ SOP.apInjs_POP pop   ∷ SOP (m :.: Result t) xss
      2. By hsequence ∷ (SListIN h xs, SListIN (Prod h) xs, HSequence h, Applicative f) =>
          h f xs -> f (h I xs)
      3. Comp msop = hsequence ct                ∷     (m :.: Result t) (SOP I xss)
      4. By unComp ∷
          (f :.: g) p -> f (g p)
      5. msop                                    ∷      m    (Result t  (SOP I xss))
      6. By (SOP.to <$>) <$>
          m (Result t (SOP I (x : xs))) -> m (Result t a)
      7. Comp res = (SOP.to <$>) <$> msop        ∷     (m :.: Result t) a
      8. By unComp ∷
          (f :.: g) p -> f (g p)
      9. res                                     ∷      m    (Result t a)
***** Potential `hsequence` replacements
      - hsequence' ∷ (SListIN h xs, Applicative f) ⇒ h (f :.: g) xs → f (h g xs)
        hsequence  ∷                                 h  f        xs → f (h I xs)
        htraverse' ∷ (SListI2 xss, Applicative g) =>
                     (forall a ⇒ f a → g (f' a)) → SOP f xss → g (SOP f' xss)
      - g ~ m, f' ~ Result t
        -            (forall a ⇒ f a → m (Result t a)) → SOP f xss → m (SOP (Result t) xss)
***** The problematic foundation of the pipeline
      1. forall f xs. (c a, All c xs, All2 c xss)
         ⇒ …
         → (a → f)
         → (m :.: Result t) f
      2. We want to separate (Result t f) from f
      3. Theory: can we go for this instead:
         → m (Result t f)
      4. Let's try!
***** Solution
      - introduce a separate node finalisation post-phase, that performs monadic
        computation after the ADT lift
*** GHC-8.8
    - cabal-doctest
      - [X] fetchpatch
    - cabal-install
      - [X] bump for Cabal
    - generic-deriving
      - [X] bump for TH
    - data-default
      - [ ] ???
        - ["cp", "-f", "/nix/store/baa1q5ph9w2daw63vdblldq4wc5g74c0-data-default-class-0.1.2.0/lib/ghc-8.7.20190115/package.conf.d/data-default-class-0.1.2.0-FeIQ5tLoVZBHMSgrT9zptQ.conf", "/build/package.conf.d/"]
        - ["cp", "-f", "/build/package.conf.d/"]
    - haskell-src-exts
      - [ ] sigsegv in Haddock
    - gtk2hs-buildtools
      - [ ] MonadFail https://github.com/gtk2hs/gtk2hs/issues/264
    - th-lift
      - [ ] TH https://github.com/mboes/th-lift/issues/38
    - generics-sop
      - [ ] TH https://github.com/well-typed/generics-sop/issues/96
* emacs options

;; Local Variables:
;; eval: (setf indent-tabs-mode nil org-todo-keyword-faces '(("TODO" . "#6c71c4") ("START" . "#2aa198") ("CODE" . "#6c71c4") ("SORTA" . "#268bd2") ("DONE" . "#073642") ("UPSTREAM" . "#268bd2")))
;; End:

{'fraction_non_alphanumeric': 0.09499327808063349, 'fraction_numerical': 0.0107550709864232, 'mean_word_length': 1.5328344246959775, 'pattern_counts': {'":': 2, '<': 23, '<?xml version=': 0, '>': 41, 'https://': 43, 'lorem ipsum': 0, 'www.': 16, 'xml': 0}, 'pii_count': 4, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 120, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '699080', 'n_tokens_mistral': 18886, 'n_tokens_neox': 17466, 'n_words': 6461}