Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Linear structures lightning talk
1. • Order
by construction / sorted / random
• Evaluation
eager / lazy
• Peek
first / last / indexed
• Construction
first / last / insert
• Remove (Deconstruct)
first / last / indexed
choose 1
choose 1
choose 1 – 2, or #3
choose 0 – 2, or #3
choose 0 – 2, or #3
(insert only for sorted & random)
4. Breadth 1st Traversal
let inline breadth1stForest forest =
let rec loop acc dl =
match dl with
| DList.Nil -> acc
| DList.Cons(head, tail) ->
loop (Queue.conj head.Root acc)
(DList.append tail (DList.ofSeq head.Children))
loop Queue.empty (DList.ofSeq forest)
Hinweis der Redaktion
It's fair to say the singly-linked list is the foundational linear data structure of functional programming. With it you can do most anything you can ask of a linear data structure or a linked data structure, but not always efficiently; and not just efficiency in terms of computational resources, but also expressively efficient.Disregarding for the moment range operations, let's look at the characteristics of and actions on linear data structures.Order is usually by construction, representing the order of the sequence consumed to create the structure, and/or the order individual elements were added. Sorted or even a random order is however possible.Evaluation in F# is eager by default, so you have to go out of your way to lazily evaluate anything (except sequences).Construction, peeking, and removing (or de-construction) are all the same for the singly-linked list (i.e. cons/tail), it always takes place at the beginning, but we might want a structure that mixes this up in any conceivable combination.If you work out the combinatorics, you would have a ridiculous number of potential signatures, but lazy evaluation for instance is not practical or desirable in most signatures, and there are only about a half dozen or so configurations that are uniquely useful as purely functional data structures.But the unifying theme here, indeed the concept that orients us across linear structures is sequence.
Let's look at 3 structures available in FSharpx.Collections. If you don't know about FSharpx, it's an open source foundational library for F# maintained in Github and available through NuGet.1) Steffen Forkmann’s implementation of Vector from Clojure. It implements a hash array mapped trie internally. It’s very fast, gives you essentially all the functionality of F# Array, with the added qualities of persistence and the ability to grow and shrink efficiently at the end of the sequence. Vector is probably the most versatile and performant purely functional structure for covering most of your needs involving eager evaluation since it includes indexed lookup and update.2) Queue, a persistent implementation of the well-known FIFO structure.3) DList (append list), this structure's signature in some ways marries the Queue and the singly linked list, with the added benefit we can not only enqueue single elements, but actually append an additional DList.So let's look at an example of how we can use purely functional linear structures to efficiently express program intent.
Let's take the example of a Multiway Forest. Many kinds of documents can assume this form, HTML, XML, JSON docs, for example. We could model the sequences represented here with any linear data structure. Let's say it's Vector for arguments sake, and let's say the task at hand is to do a breadth first traversal.
The ease of composing linear structures lets us transform the forest segments across a range of structures. We use the canonical recursive loop over match.Our end product is a Queue so we seed it with an empty Queue, and start by transforming the top level forest segment into a DList. (Remember how sequence orients us across all linear structures? It also provides us with graceful transforms from any linear structure to any other.)Looping through the match, we deconstruct the DList into head and tail. Enqueue the data in the head element (note "conj" is the common function name across the FSharpx.Collections linear structures for adding an element on the right), and transform the head's children segment into a DList. This gets appended to the tail from the deconstruction and cycled through the loop. (Conveniently, "append" is an O(1) operation.)When the DList is empty output the accumulated Queue.