<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html> <head> <!-- Generated by HsColour, http://www.cs.york.ac.uk/fp/darcs/hscolour/ --> <title>src/Data/MemoTrie.hs</title> <link type='text/css' rel='stylesheet' href='hscolour.css' /> </head> <body> <pre><a name="line-1"></a><span class='hs-comment'>{-# LANGUAGE GADTs, TypeFamilies, TypeOperators, ScopedTypeVariables, CPP #-}</span> <a name="line-2"></a><span class='hs-comment'>{-# OPTIONS_GHC -Wall -fenable-rewrite-rules #-}</span> <a name="line-3"></a><span class='hs-comment'>-- ScopedTypeVariables works around a 6.10 bug. The forall keyword is</span> <a name="line-4"></a><span class='hs-comment'>-- supposed to be recognized in a RULES pragma.</span> <a name="line-5"></a> <a name="line-6"></a><span class='hs-comment'>----------------------------------------------------------------------</span> <a name="line-7"></a><span class='hs-comment'>-- |</span> <a name="line-8"></a><span class='hs-comment'>-- Module : Data.MemoTrie</span> <a name="line-9"></a><span class='hs-comment'>-- Copyright : (c) Conal Elliott 2008</span> <a name="line-10"></a><span class='hs-comment'>-- License : BSD3</span> <a name="line-11"></a><span class='hs-comment'>-- </span> <a name="line-12"></a><span class='hs-comment'>-- Maintainer : conal@conal.net</span> <a name="line-13"></a><span class='hs-comment'>-- Stability : experimental</span> <a name="line-14"></a><span class='hs-comment'>-- </span> <a name="line-15"></a><span class='hs-comment'>-- Trie-based memoizer</span> <a name="line-16"></a><span class='hs-comment'>-- Adapted from sjanssen's paste: \"a lazy trie\" <<a href="http://hpaste.org/3839">http://hpaste.org/3839</a>>.</span> <a name="line-17"></a><span class='hs-comment'>----------------------------------------------------------------------</span> <a name="line-18"></a> <a name="line-19"></a><span class='hs-keyword'>module</span> <span class='hs-conid'>Data</span><span class='hs-varop'>.</span><span class='hs-conid'>MemoTrie</span> <a name="line-20"></a> <span class='hs-layout'>(</span> <span class='hs-conid'>HasTrie</span><span class='hs-layout'>(</span><span class='hs-keyglyph'>..</span><span class='hs-layout'>)</span><span class='hs-layout'>,</span> <span class='hs-varid'>domain</span><span class='hs-layout'>,</span> <span class='hs-varid'>idTrie</span><span class='hs-layout'>,</span> <span class='hs-layout'>(</span><span class='hs-varop'>@.@</span><span class='hs-layout'>)</span> <a name="line-21"></a> <span class='hs-comment'>-- , trie2, trie3, untrie2, untrie3</span> <a name="line-22"></a> <span class='hs-layout'>,</span> <span class='hs-varid'>memo</span><span class='hs-layout'>,</span> <span class='hs-varid'>memo2</span><span class='hs-layout'>,</span> <span class='hs-varid'>memo3</span><span class='hs-layout'>,</span> <span class='hs-varid'>mup</span> <a name="line-23"></a> <span class='hs-layout'>,</span> <span class='hs-varid'>inTrie</span><span class='hs-layout'>,</span> <span class='hs-varid'>inTrie2</span><span class='hs-layout'>,</span> <span class='hs-varid'>inTrie3</span> <a name="line-24"></a> <span class='hs-comment'>-- , untrieBits</span> <a name="line-25"></a> <span class='hs-layout'>)</span> <span class='hs-keyword'>where</span> <a name="line-26"></a> <a name="line-27"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Data</span><span class='hs-varop'>.</span><span class='hs-conid'>Bits</span> <a name="line-28"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Data</span><span class='hs-varop'>.</span><span class='hs-conid'>Word</span> <a name="line-29"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Data</span><span class='hs-varop'>.</span><span class='hs-conid'>Int</span> <a name="line-30"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Control</span><span class='hs-varop'>.</span><span class='hs-conid'>Applicative</span> <a name="line-31"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Control</span><span class='hs-varop'>.</span><span class='hs-conid'>Arrow</span> <span class='hs-layout'>(</span><span class='hs-varid'>first</span><span class='hs-layout'>,</span><span class='hs-layout'>(</span><span class='hs-varop'>&&&</span><span class='hs-layout'>)</span><span class='hs-layout'>)</span> <a name="line-32"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Data</span><span class='hs-varop'>.</span><span class='hs-conid'>Monoid</span> <a name="line-33"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Data</span><span class='hs-varop'>.</span><span class='hs-conid'>Function</span> <span class='hs-layout'>(</span><span class='hs-varid'>on</span><span class='hs-layout'>)</span> <a name="line-34"></a> <a name="line-35"></a><span class='hs-comment'>-- import Prelude hiding (id,(.))</span> <a name="line-36"></a><span class='hs-comment'>-- import Control.Category</span> <a name="line-37"></a><span class='hs-comment'>-- import Control.Arrow</span> <a name="line-38"></a> <a name="line-39"></a><span class='hs-keyword'>infixr</span> <span class='hs-num'>0</span> <span class='hs-conop'>:->:</span> <a name="line-40"></a> <a name="line-41"></a><span class='hs-comment'>-- | Mapping from all elements of @a@ to the results of some function</span> <a name="line-42"></a><span class='hs-keyword'>class</span> <span class='hs-conid'>HasTrie</span> <span class='hs-varid'>a</span> <span class='hs-keyword'>where</span> <a name="line-43"></a> <span class='hs-comment'>-- | Representation of trie with domain type @a@</span> <a name="line-44"></a> <span class='hs-keyword'>data</span> <span class='hs-layout'>(</span><span class='hs-conop'>:->:</span><span class='hs-layout'>)</span> <span class='hs-varid'>a</span> <span class='hs-keyglyph'>::</span> <span class='hs-varop'>*</span> <span class='hs-keyglyph'>-></span> <span class='hs-varop'>*</span> <a name="line-45"></a> <span class='hs-comment'>-- | Create the trie for the entire domain of a function</span> <a name="line-46"></a> <span class='hs-varid'>trie</span> <span class='hs-keyglyph'>::</span> <span class='hs-layout'>(</span><span class='hs-varid'>a</span> <span class='hs-keyglyph'>-></span> <span class='hs-varid'>b</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>-></span> <span class='hs-layout'>(</span><span class='hs-varid'>a</span> <span class='hs-conop'>:->:</span> <span class='hs-varid'>b</span><span class='hs-layout'>)</span> <a name="line-47"></a> <span class='hs-comment'>-- | Convert a trie to a function, i.e., access a field of the trie</span> <a name="line-48"></a> <span class='hs-varid'>untrie</span> <span class='hs-keyglyph'>::</span> <span class='hs-layout'>(</span><span class='hs-varid'>a</span> <span class='hs-conop'>:->:</span> <span class='hs-varid'>b</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>-></span> <span class='hs-layout'>(</span><span class='hs-varid'>a</span> <span class='hs-keyglyph'>-></span> <span class='hs-varid'>b</span><span class='hs-layout'>)</span> <a name="line-49"></a> <span class='hs-comment'>-- | List the trie elements. Order of keys (@:: a@) is always the same.</span> <a name="line-50"></a> <span class='hs-varid'>enumerate</span> <span class='hs-keyglyph'>::</span> <span class='hs-layout'>(</span><span class='hs-varid'>a</span> <span class='hs-conop'>:->:</span> <span class='hs-varid'>b</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>-></span> <span class='hs-keyglyph'>[</span><span class='hs-layout'>(</span><span class='hs-varid'>a</span><span class='hs-layout'>,</span><span class='hs-varid'>b</span><span class='hs-layout'>)</span><span class='hs-keyglyph'>]</span> <a name="line-51"></a> <a name="line-52"></a><a name="domain"></a><span class='hs-comment'>-- | Domain elements of a trie</span> <a name="line-53"></a><span class='hs-definition'>domain</span> <span class='hs-keyglyph'>::</span> <span class='hs-conid'>HasTrie</span> <span class='hs-varid'>a</span> <span class='hs-keyglyph'>=></span> <span class='hs-keyglyph'>[</span><span class='hs-varid'>a</span><span class='hs-keyglyph'>]</span> <a name="line-54"></a><span class='hs-definition'>domain</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>map</span> <span class='hs-varid'>fst</span> <span class='hs-layout'>(</span><span class='hs-varid'>enumerate</span> <span class='hs-layout'>(</span><span class='hs-varid'>trie</span> <span class='hs-layout'>(</span><span class='hs-varid'>const</span> <span class='hs-varid'>oops</span><span class='hs-layout'>)</span><span class='hs-layout'>)</span><span class='hs-layout'>)</span> <a name="line-55"></a> <span class='hs-keyword'>where</span> <a name="line-56"></a> <span class='hs-varid'>oops</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>error</span> <span class='hs-str'>"Data.MemoTrie.domain: range element evaluated."</span> <a name="line-57"></a> <a name="line-58"></a><span class='hs-comment'>-- Hm: domain :: [Bool] doesn't produce any output.</span> <a name="line-59"></a> <a name="line-60"></a><span class='hs-keyword'>instance</span> <span class='hs-layout'>(</span><span class='hs-conid'>HasTrie</span> <span class='hs-varid'>a</span><span class='hs-layout'>,</span> <span class='hs-conid'>Eq</span> <span class='hs-varid'>b</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=></span> <span class='hs-conid'>Eq</span> <span class='hs-layout'>(</span><span class='hs-varid'>a</span> <span class='hs-conop'>:->:</span> <span class='hs-varid'>b</span><span class='hs-layout'>)</span> <span class='hs-keyword'>where</span> <a name="line-61"></a> <span class='hs-layout'>(</span><span class='hs-varop'>==</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=</span> <span class='hs-layout'>(</span><span class='hs-varop'>==</span><span class='hs-layout'>)</span> <span class='hs-varop'>`on`</span> <span class='hs-layout'>(</span><span class='hs-varid'>map</span> <span class='hs-varid'>snd</span> <span class='hs-varop'>.</span> <span class='hs-varid'>enumerate</span><span class='hs-layout'>)</span> <a name="line-62"></a> <a name="line-63"></a><span class='hs-keyword'>instance</span> <span class='hs-layout'>(</span><span class='hs-conid'>HasTrie</span> <span class='hs-varid'>a</span><span class='hs-layout'>,</span> <span class='hs-conid'>Show</span> <span class='hs-varid'>a</span><span class='hs-layout'>,</span> <span class='hs-conid'>Show</span> <span class='hs-varid'>b</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=></span> <span class='hs-conid'>Show</span> <span class='hs-layout'>(</span><span class='hs-varid'>a</span> <span class='hs-conop'>:->:</span> <span class='hs-varid'>b</span><span class='hs-layout'>)</span> <span class='hs-keyword'>where</span> <a name="line-64"></a> <span class='hs-varid'>show</span> <span class='hs-varid'>t</span> <span class='hs-keyglyph'>=</span> <span class='hs-str'>"Trie: "</span> <span class='hs-varop'>++</span> <span class='hs-varid'>show</span> <span class='hs-layout'>(</span><span class='hs-varid'>enumerate</span> <span class='hs-varid'>t</span><span class='hs-layout'>)</span> <a name="line-65"></a> <a name="line-66"></a><span class='hs-comment'>{- <a name="line-67"></a>trie2 :: (HasTrie a, HasTrie b) => <a name="line-68"></a> (a -> b -> c) -> (a :->: b :->: c) <a name="line-69"></a>-- trie2 h = trie $ \ a -> trie $ \ b -> h a b <a name="line-70"></a>-- trie2 h = trie $ \ a -> trie (h a) <a name="line-71"></a>trie2 h = trie (trie . h) <a name="line-72"></a>-- trie2 h = trie (fmap trie h) <a name="line-73"></a>-- trie2 = (fmap.fmap) trie trie <a name="line-74"></a> <a name="line-75"></a> <a name="line-76"></a>trie3 :: (HasTrie a, HasTrie b, HasTrie c) => <a name="line-77"></a> (a -> b -> c -> d) -> (a :->: b :->: c :->: d) <a name="line-78"></a>trie3 h = trie (trie2 . h) <a name="line-79"></a> <a name="line-80"></a>untrie2 :: (HasTrie a, HasTrie b) => <a name="line-81"></a> (a :->: b :->: c)-> (a -> b -> c) <a name="line-82"></a>untrie2 tt = untrie . untrie tt <a name="line-83"></a> <a name="line-84"></a> <a name="line-85"></a>untrie3 :: (HasTrie a, HasTrie b, HasTrie c) => <a name="line-86"></a> (a :->: b :->: c :->: d)-> (a -> b -> c -> d) <a name="line-87"></a>untrie3 tt = untrie2 . untrie tt <a name="line-88"></a>-}</span> <a name="line-89"></a> <a name="line-90"></a> <a name="line-91"></a><span class='hs-comment'>{-# RULES <a name="line-92"></a>"trie/untrie" forall t. trie (untrie t) = t <a name="line-93"></a> #-}</span> <a name="line-94"></a> <a name="line-95"></a><span class='hs-comment'>-- Don't include the dual rule:</span> <a name="line-96"></a><span class='hs-comment'>-- "untrie/trie" forall f. untrie (trie f) = f</span> <a name="line-97"></a><span class='hs-comment'>-- which would defeat memoization.</span> <a name="line-98"></a><span class='hs-comment'>--</span> <a name="line-99"></a><span class='hs-comment'>-- TODO: experiment with rule application. Maybe re-enable "untrie/trie"</span> <a name="line-100"></a><span class='hs-comment'>-- but fiddle with phases, so it won't defeat 'memo'.</span> <a name="line-101"></a> <a name="line-102"></a><a name="memo"></a><span class='hs-comment'>-- | Trie-based function memoizer</span> <a name="line-103"></a><span class='hs-definition'>memo</span> <span class='hs-keyglyph'>::</span> <span class='hs-conid'>HasTrie</span> <span class='hs-varid'>t</span> <span class='hs-keyglyph'>=></span> <span class='hs-layout'>(</span><span class='hs-varid'>t</span> <span class='hs-keyglyph'>-></span> <span class='hs-varid'>a</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>-></span> <span class='hs-layout'>(</span><span class='hs-varid'>t</span> <span class='hs-keyglyph'>-></span> <span class='hs-varid'>a</span><span class='hs-layout'>)</span> <a name="line-104"></a><span class='hs-definition'>memo</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>untrie</span> <span class='hs-varop'>.</span> <span class='hs-varid'>trie</span> <a name="line-105"></a> <a name="line-106"></a><a name="memo2"></a><span class='hs-comment'>-- | Memoize a binary function, on its first argument and then on its</span> <a name="line-107"></a><span class='hs-comment'>-- second. Take care to exploit any partial evaluation.</span> <a name="line-108"></a><span class='hs-definition'>memo2</span> <span class='hs-keyglyph'>::</span> <span class='hs-layout'>(</span><span class='hs-conid'>HasTrie</span> <span class='hs-varid'>s</span><span class='hs-layout'>,</span><span class='hs-conid'>HasTrie</span> <span class='hs-varid'>t</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=></span> <span class='hs-layout'>(</span><span class='hs-varid'>s</span> <span class='hs-keyglyph'>-></span> <span class='hs-varid'>t</span> <span class='hs-keyglyph'>-></span> <span class='hs-varid'>a</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>-></span> <span class='hs-layout'>(</span><span class='hs-varid'>s</span> <span class='hs-keyglyph'>-></span> <span class='hs-varid'>t</span> <span class='hs-keyglyph'>-></span> <span class='hs-varid'>a</span><span class='hs-layout'>)</span> <a name="line-109"></a> <a name="line-110"></a><a name="memo3"></a><span class='hs-comment'>-- | Memoize a ternary function on successive arguments. Take care to</span> <a name="line-111"></a><span class='hs-comment'>-- exploit any partial evaluation.</span> <a name="line-112"></a><span class='hs-definition'>memo3</span> <span class='hs-keyglyph'>::</span> <span class='hs-layout'>(</span><span class='hs-conid'>HasTrie</span> <span class='hs-varid'>r</span><span class='hs-layout'>,</span><span class='hs-conid'>HasTrie</span> <span class='hs-varid'>s</span><span class='hs-layout'>,</span><span class='hs-conid'>HasTrie</span> <span class='hs-varid'>t</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=></span> <span class='hs-layout'>(</span><span class='hs-varid'>r</span> <span class='hs-keyglyph'>-></span> <span class='hs-varid'>s</span> <span class='hs-keyglyph'>-></span> <span class='hs-varid'>t</span> <span class='hs-keyglyph'>-></span> <span class='hs-varid'>a</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>-></span> <span class='hs-layout'>(</span><span class='hs-varid'>r</span> <span class='hs-keyglyph'>-></span> <span class='hs-varid'>s</span> <span class='hs-keyglyph'>-></span> <span class='hs-varid'>t</span> <span class='hs-keyglyph'>-></span> <span class='hs-varid'>a</span><span class='hs-layout'>)</span> <a name="line-113"></a> <a name="line-114"></a><a name="mup"></a><span class='hs-comment'>-- | Lift a memoizer to work with one more argument.</span> <a name="line-115"></a><span class='hs-definition'>mup</span> <span class='hs-keyglyph'>::</span> <span class='hs-conid'>HasTrie</span> <span class='hs-varid'>t</span> <span class='hs-keyglyph'>=></span> <span class='hs-layout'>(</span><span class='hs-varid'>b</span> <span class='hs-keyglyph'>-></span> <span class='hs-varid'>c</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>-></span> <span class='hs-layout'>(</span><span class='hs-varid'>t</span> <span class='hs-keyglyph'>-></span> <span class='hs-varid'>b</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>-></span> <span class='hs-layout'>(</span><span class='hs-varid'>t</span> <span class='hs-keyglyph'>-></span> <span class='hs-varid'>c</span><span class='hs-layout'>)</span> <a name="line-116"></a><span class='hs-definition'>mup</span> <span class='hs-varid'>mem</span> <span class='hs-varid'>f</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>memo</span> <span class='hs-layout'>(</span><span class='hs-varid'>mem</span> <span class='hs-varop'>.</span> <span class='hs-varid'>f</span><span class='hs-layout'>)</span> <a name="line-117"></a> <a name="line-118"></a><span class='hs-definition'>memo2</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>mup</span> <span class='hs-varid'>memo</span> <a name="line-119"></a><span class='hs-definition'>memo3</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>mup</span> <span class='hs-varid'>memo2</span> <a name="line-120"></a> <a name="line-121"></a><a name="inTrie"></a><span class='hs-comment'>-- | Apply a unary function inside of a trie</span> <a name="line-122"></a><span class='hs-definition'>inTrie</span> <span class='hs-keyglyph'>::</span> <span class='hs-layout'>(</span><span class='hs-conid'>HasTrie</span> <span class='hs-varid'>a</span><span class='hs-layout'>,</span> <span class='hs-conid'>HasTrie</span> <span class='hs-varid'>c</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=></span> <a name="line-123"></a> <span class='hs-layout'>(</span><span class='hs-layout'>(</span><span class='hs-varid'>a</span> <span class='hs-keyglyph'>-></span> <span class='hs-varid'>b</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>-></span> <span class='hs-layout'>(</span><span class='hs-varid'>c</span> <span class='hs-keyglyph'>-></span> <span class='hs-varid'>d</span><span class='hs-layout'>)</span><span class='hs-layout'>)</span> <a name="line-124"></a> <span class='hs-keyglyph'>-></span> <span class='hs-layout'>(</span><span class='hs-layout'>(</span><span class='hs-varid'>a</span> <span class='hs-conop'>:->:</span> <span class='hs-varid'>b</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>-></span> <span class='hs-layout'>(</span><span class='hs-varid'>c</span> <span class='hs-conop'>:->:</span> <span class='hs-varid'>d</span><span class='hs-layout'>)</span><span class='hs-layout'>)</span> <a name="line-125"></a><span class='hs-definition'>inTrie</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>untrie</span> <span class='hs-varop'>~></span> <span class='hs-varid'>trie</span> <a name="line-126"></a> <a name="line-127"></a><a name="inTrie2"></a><span class='hs-comment'>-- | Apply a binary function inside of a trie</span> <a name="line-128"></a><span class='hs-definition'>inTrie2</span> <span class='hs-keyglyph'>::</span> <span class='hs-layout'>(</span><span class='hs-conid'>HasTrie</span> <span class='hs-varid'>a</span><span class='hs-layout'>,</span> <span class='hs-conid'>HasTrie</span> <span class='hs-varid'>c</span><span class='hs-layout'>,</span> <span class='hs-conid'>HasTrie</span> <span class='hs-varid'>e</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=></span> <a name="line-129"></a> <span class='hs-layout'>(</span><span class='hs-layout'>(</span><span class='hs-varid'>a</span> <span class='hs-keyglyph'>-></span> <span class='hs-varid'>b</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>-></span> <span class='hs-layout'>(</span><span class='hs-varid'>c</span> <span class='hs-keyglyph'>-></span> <span class='hs-varid'>d</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>-></span> <span class='hs-layout'>(</span><span class='hs-varid'>e</span> <span class='hs-keyglyph'>-></span> <span class='hs-varid'>f</span><span class='hs-layout'>)</span><span class='hs-layout'>)</span> <a name="line-130"></a> <span class='hs-keyglyph'>-></span> <span class='hs-layout'>(</span><span class='hs-layout'>(</span><span class='hs-varid'>a</span> <span class='hs-conop'>:->:</span> <span class='hs-varid'>b</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>-></span> <span class='hs-layout'>(</span><span class='hs-varid'>c</span> <span class='hs-conop'>:->:</span> <span class='hs-varid'>d</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>-></span> <span class='hs-layout'>(</span><span class='hs-varid'>e</span> <span class='hs-conop'>:->:</span> <span class='hs-varid'>f</span><span class='hs-layout'>)</span><span class='hs-layout'>)</span> <a name="line-131"></a><span class='hs-definition'>inTrie2</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>untrie</span> <span class='hs-varop'>~></span> <span class='hs-varid'>inTrie</span> <a name="line-132"></a> <a name="line-133"></a><a name="inTrie3"></a><span class='hs-comment'>-- | Apply a ternary function inside of a trie</span> <a name="line-134"></a><span class='hs-definition'>inTrie3</span> <span class='hs-keyglyph'>::</span> <span class='hs-layout'>(</span><span class='hs-conid'>HasTrie</span> <span class='hs-varid'>a</span><span class='hs-layout'>,</span> <span class='hs-conid'>HasTrie</span> <span class='hs-varid'>c</span><span class='hs-layout'>,</span> <span class='hs-conid'>HasTrie</span> <span class='hs-varid'>e</span><span class='hs-layout'>,</span> <span class='hs-conid'>HasTrie</span> <span class='hs-varid'>g</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=></span> <a name="line-135"></a> <span class='hs-layout'>(</span><span class='hs-layout'>(</span><span class='hs-varid'>a</span> <span class='hs-keyglyph'>-></span> <span class='hs-varid'>b</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>-></span> <span class='hs-layout'>(</span><span class='hs-varid'>c</span> <span class='hs-keyglyph'>-></span> <span class='hs-varid'>d</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>-></span> <span class='hs-layout'>(</span><span class='hs-varid'>e</span> <span class='hs-keyglyph'>-></span> <span class='hs-varid'>f</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>-></span> <span class='hs-layout'>(</span><span class='hs-varid'>g</span> <span class='hs-keyglyph'>-></span> <span class='hs-varid'>h</span><span class='hs-layout'>)</span><span class='hs-layout'>)</span> <a name="line-136"></a> <span class='hs-keyglyph'>-></span> <span class='hs-layout'>(</span><span class='hs-layout'>(</span><span class='hs-varid'>a</span> <span class='hs-conop'>:->:</span> <span class='hs-varid'>b</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>-></span> <span class='hs-layout'>(</span><span class='hs-varid'>c</span> <span class='hs-conop'>:->:</span> <span class='hs-varid'>d</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>-></span> <span class='hs-layout'>(</span><span class='hs-varid'>e</span> <span class='hs-conop'>:->:</span> <span class='hs-varid'>f</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>-></span> <span class='hs-layout'>(</span><span class='hs-varid'>g</span> <span class='hs-conop'>:->:</span> <span class='hs-varid'>h</span><span class='hs-layout'>)</span><span class='hs-layout'>)</span> <a name="line-137"></a><span class='hs-definition'>inTrie3</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>untrie</span> <span class='hs-varop'>~></span> <span class='hs-varid'>inTrie2</span> <a name="line-138"></a> <a name="line-139"></a> <a name="line-140"></a><span class='hs-comment'>---- Instances</span> <a name="line-141"></a> <a name="line-142"></a><span class='hs-keyword'>instance</span> <span class='hs-conid'>HasTrie</span> <span class='hs-conid'>()</span> <span class='hs-keyword'>where</span> <a name="line-143"></a> <span class='hs-keyword'>data</span> <span class='hs-conid'>()</span> <span class='hs-conop'>:->:</span> <span class='hs-varid'>a</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>UnitTrie</span> <span class='hs-varid'>a</span> <a name="line-144"></a> <span class='hs-varid'>trie</span> <span class='hs-varid'>f</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>UnitTrie</span> <span class='hs-layout'>(</span><span class='hs-varid'>f</span> <span class='hs-conid'>()</span><span class='hs-layout'>)</span> <a name="line-145"></a> <span class='hs-varid'>untrie</span> <span class='hs-layout'>(</span><span class='hs-conid'>UnitTrie</span> <span class='hs-varid'>a</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=</span> <span class='hs-keyglyph'>\</span> <span class='hs-conid'>()</span> <span class='hs-keyglyph'>-></span> <span class='hs-varid'>a</span> <a name="line-146"></a> <span class='hs-varid'>enumerate</span> <span class='hs-layout'>(</span><span class='hs-conid'>UnitTrie</span> <span class='hs-varid'>a</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=</span> <span class='hs-keyglyph'>[</span><span class='hs-layout'>(</span><span class='hs-conid'>()</span><span class='hs-layout'>,</span><span class='hs-varid'>a</span><span class='hs-layout'>)</span><span class='hs-keyglyph'>]</span> <a name="line-147"></a> <a name="line-148"></a><span class='hs-comment'>-- Proofs of inverse properties:</span> <a name="line-149"></a> <a name="line-150"></a><span class='hs-comment'>{- <a name="line-151"></a> untrie (trie f) <a name="line-152"></a> == { trie def } <a name="line-153"></a> untrie (UnitTrie (f ())) <a name="line-154"></a> == { untrie def } <a name="line-155"></a> \ () -> (f ()) <a name="line-156"></a> == { const-unit } <a name="line-157"></a> f <a name="line-158"></a> <a name="line-159"></a> trie (untrie (UnitTrie a)) <a name="line-160"></a> == { untrie def } <a name="line-161"></a> trie (\ () -> a) <a name="line-162"></a> == { trie def } <a name="line-163"></a> UnitTrie ((\ () -> a) ()) <a name="line-164"></a> == { beta-reduction } <a name="line-165"></a> UnitTrie a <a name="line-166"></a> <a name="line-167"></a>Oops -- the last step of the first direction is bogus when f is non-strict. <a name="line-168"></a>Can be fixed by using @const a@ in place of @\ () -> a@, but I can't do <a name="line-169"></a>the same for other types, like integers or sums. <a name="line-170"></a> <a name="line-171"></a>All of these proofs have this same bug, unless we restrict ourselves to <a name="line-172"></a>memoizing hyper-strict functions. <a name="line-173"></a> <a name="line-174"></a>-}</span> <a name="line-175"></a> <a name="line-176"></a> <a name="line-177"></a><span class='hs-keyword'>instance</span> <span class='hs-conid'>HasTrie</span> <span class='hs-conid'>Bool</span> <span class='hs-keyword'>where</span> <a name="line-178"></a> <span class='hs-keyword'>data</span> <span class='hs-conid'>Bool</span> <span class='hs-conop'>:->:</span> <span class='hs-varid'>x</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>BoolTrie</span> <span class='hs-varid'>x</span> <span class='hs-varid'>x</span> <a name="line-179"></a> <span class='hs-varid'>trie</span> <span class='hs-varid'>f</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>BoolTrie</span> <span class='hs-layout'>(</span><span class='hs-varid'>f</span> <span class='hs-conid'>False</span><span class='hs-layout'>)</span> <span class='hs-layout'>(</span><span class='hs-varid'>f</span> <span class='hs-conid'>True</span><span class='hs-layout'>)</span> <a name="line-180"></a> <span class='hs-varid'>untrie</span> <span class='hs-layout'>(</span><span class='hs-conid'>BoolTrie</span> <span class='hs-varid'>f</span> <span class='hs-varid'>t</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>if'</span> <span class='hs-varid'>f</span> <span class='hs-varid'>t</span> <a name="line-181"></a> <span class='hs-varid'>enumerate</span> <span class='hs-layout'>(</span><span class='hs-conid'>BoolTrie</span> <span class='hs-varid'>f</span> <span class='hs-varid'>t</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=</span> <span class='hs-keyglyph'>[</span><span class='hs-layout'>(</span><span class='hs-conid'>False</span><span class='hs-layout'>,</span><span class='hs-varid'>f</span><span class='hs-layout'>)</span><span class='hs-layout'>,</span><span class='hs-layout'>(</span><span class='hs-conid'>True</span><span class='hs-layout'>,</span><span class='hs-varid'>t</span><span class='hs-layout'>)</span><span class='hs-keyglyph'>]</span> <a name="line-182"></a> <a name="line-183"></a><a name="if'"></a><span class='hs-comment'>-- | Conditional with boolean last.</span> <a name="line-184"></a><span class='hs-comment'>-- Spec: @if' (f False) (f True) == f@</span> <a name="line-185"></a><span class='hs-definition'>if'</span> <span class='hs-keyglyph'>::</span> <span class='hs-varid'>x</span> <span class='hs-keyglyph'>-></span> <span class='hs-varid'>x</span> <span class='hs-keyglyph'>-></span> <span class='hs-conid'>Bool</span> <span class='hs-keyglyph'>-></span> <span class='hs-varid'>x</span> <a name="line-186"></a><span class='hs-definition'>if'</span> <span class='hs-varid'>t</span> <span class='hs-keyword'>_</span> <span class='hs-conid'>False</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>t</span> <a name="line-187"></a><span class='hs-definition'>if'</span> <span class='hs-keyword'>_</span> <span class='hs-varid'>e</span> <span class='hs-conid'>True</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>e</span> <a name="line-188"></a> <a name="line-189"></a><span class='hs-comment'>{- <a name="line-190"></a> untrie (trie f) <a name="line-191"></a> == { trie def } <a name="line-192"></a> untrie (BoolTrie (f False) (f True)) <a name="line-193"></a> == { untrie def } <a name="line-194"></a> if' (f False) (f True) <a name="line-195"></a> == { if' spec } <a name="line-196"></a> f <a name="line-197"></a> <a name="line-198"></a> trie (untrie (BoolTrie f t)) <a name="line-199"></a> == { untrie def } <a name="line-200"></a> trie (if' f t) <a name="line-201"></a> == { trie def } <a name="line-202"></a> BoolTrie (if' f t False) (if' f t True) <a name="line-203"></a> == { if' spec } <a name="line-204"></a> BoolTrie f t <a name="line-205"></a>-}</span> <a name="line-206"></a> <a name="line-207"></a> <a name="line-208"></a><span class='hs-keyword'>instance</span> <span class='hs-layout'>(</span><span class='hs-conid'>HasTrie</span> <span class='hs-varid'>a</span><span class='hs-layout'>,</span> <span class='hs-conid'>HasTrie</span> <span class='hs-varid'>b</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=></span> <span class='hs-conid'>HasTrie</span> <span class='hs-layout'>(</span><span class='hs-conid'>Either</span> <span class='hs-varid'>a</span> <span class='hs-varid'>b</span><span class='hs-layout'>)</span> <span class='hs-keyword'>where</span> <a name="line-209"></a> <span class='hs-keyword'>data</span> <span class='hs-layout'>(</span><span class='hs-conid'>Either</span> <span class='hs-varid'>a</span> <span class='hs-varid'>b</span><span class='hs-layout'>)</span> <span class='hs-conop'>:->:</span> <span class='hs-varid'>x</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>EitherTrie</span> <span class='hs-layout'>(</span><span class='hs-varid'>a</span> <span class='hs-conop'>:->:</span> <span class='hs-varid'>x</span><span class='hs-layout'>)</span> <span class='hs-layout'>(</span><span class='hs-varid'>b</span> <span class='hs-conop'>:->:</span> <span class='hs-varid'>x</span><span class='hs-layout'>)</span> <a name="line-210"></a> <span class='hs-varid'>trie</span> <span class='hs-varid'>f</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>EitherTrie</span> <span class='hs-layout'>(</span><span class='hs-varid'>trie</span> <span class='hs-layout'>(</span><span class='hs-varid'>f</span> <span class='hs-varop'>.</span> <span class='hs-conid'>Left</span><span class='hs-layout'>)</span><span class='hs-layout'>)</span> <span class='hs-layout'>(</span><span class='hs-varid'>trie</span> <span class='hs-layout'>(</span><span class='hs-varid'>f</span> <span class='hs-varop'>.</span> <span class='hs-conid'>Right</span><span class='hs-layout'>)</span><span class='hs-layout'>)</span> <a name="line-211"></a> <span class='hs-varid'>untrie</span> <span class='hs-layout'>(</span><span class='hs-conid'>EitherTrie</span> <span class='hs-varid'>s</span> <span class='hs-varid'>t</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>either</span> <span class='hs-layout'>(</span><span class='hs-varid'>untrie</span> <span class='hs-varid'>s</span><span class='hs-layout'>)</span> <span class='hs-layout'>(</span><span class='hs-varid'>untrie</span> <span class='hs-varid'>t</span><span class='hs-layout'>)</span> <a name="line-212"></a> <span class='hs-varid'>enumerate</span> <span class='hs-layout'>(</span><span class='hs-conid'>EitherTrie</span> <span class='hs-varid'>s</span> <span class='hs-varid'>t</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>enum'</span> <span class='hs-conid'>Left</span> <span class='hs-varid'>s</span> <span class='hs-varop'>`weave`</span> <span class='hs-varid'>enum'</span> <span class='hs-conid'>Right</span> <span class='hs-varid'>t</span> <a name="line-213"></a> <a name="line-214"></a><a name="enum'"></a><span class='hs-definition'>enum'</span> <span class='hs-keyglyph'>::</span> <span class='hs-layout'>(</span><span class='hs-conid'>HasTrie</span> <span class='hs-varid'>a</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=></span> <span class='hs-layout'>(</span><span class='hs-varid'>a</span> <span class='hs-keyglyph'>-></span> <span class='hs-varid'>a'</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>-></span> <span class='hs-layout'>(</span><span class='hs-varid'>a</span> <span class='hs-conop'>:->:</span> <span class='hs-varid'>b</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>-></span> <span class='hs-keyglyph'>[</span><span class='hs-layout'>(</span><span class='hs-varid'>a'</span><span class='hs-layout'>,</span> <span class='hs-varid'>b</span><span class='hs-layout'>)</span><span class='hs-keyglyph'>]</span> <a name="line-215"></a><span class='hs-definition'>enum'</span> <span class='hs-varid'>f</span> <span class='hs-keyglyph'>=</span> <span class='hs-layout'>(</span><span class='hs-varid'>fmap</span><span class='hs-varop'>.</span><span class='hs-varid'>first</span><span class='hs-layout'>)</span> <span class='hs-varid'>f</span> <span class='hs-varop'>.</span> <span class='hs-varid'>enumerate</span> <a name="line-216"></a> <a name="line-217"></a><a name="weave"></a><span class='hs-definition'>weave</span> <span class='hs-keyglyph'>::</span> <span class='hs-keyglyph'>[</span><span class='hs-varid'>a</span><span class='hs-keyglyph'>]</span> <span class='hs-keyglyph'>-></span> <span class='hs-keyglyph'>[</span><span class='hs-varid'>a</span><span class='hs-keyglyph'>]</span> <span class='hs-keyglyph'>-></span> <span class='hs-keyglyph'>[</span><span class='hs-varid'>a</span><span class='hs-keyglyph'>]</span> <a name="line-218"></a><span class='hs-conid'>[]</span> <span class='hs-varop'>`weave`</span> <span class='hs-keyword'>as</span> <span class='hs-keyglyph'>=</span> <span class='hs-keyword'>as</span> <a name="line-219"></a><span class='hs-keyword'>as</span> <span class='hs-varop'>`weave`</span> <span class='hs-conid'>[]</span> <span class='hs-keyglyph'>=</span> <span class='hs-keyword'>as</span> <a name="line-220"></a><a name="weave"></a><span class='hs-layout'>(</span><span class='hs-varid'>a</span><span class='hs-conop'>:</span><span class='hs-keyword'>as</span><span class='hs-layout'>)</span> <span class='hs-varop'>`weave`</span> <span class='hs-varid'>bs</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>a</span> <span class='hs-conop'>:</span> <span class='hs-layout'>(</span><span class='hs-varid'>bs</span> <span class='hs-varop'>`weave`</span> <span class='hs-keyword'>as</span><span class='hs-layout'>)</span> <a name="line-221"></a> <a name="line-222"></a><span class='hs-comment'>{- <a name="line-223"></a> untrie (trie f) <a name="line-224"></a> == { trie def } <a name="line-225"></a> untrie (EitherTrie (trie (f . Left)) (trie (f . Right))) <a name="line-226"></a> == { untrie def } <a name="line-227"></a> either (untrie (trie (f . Left))) (untrie (trie (f . Right))) <a name="line-228"></a> == { untrie . trie } <a name="line-229"></a> either (f . Left) (f . Right) <a name="line-230"></a> == { either } <a name="line-231"></a> f <a name="line-232"></a> <a name="line-233"></a> trie (untrie (EitherTrie s t)) <a name="line-234"></a> == { untrie def } <a name="line-235"></a> trie (either (untrie s) (untrie t)) <a name="line-236"></a> == { trie def } <a name="line-237"></a> EitherTrie (trie (either (untrie s) (untrie t) . Left)) <a name="line-238"></a> (trie (either (untrie s) (untrie t) . Right)) <a name="line-239"></a> == { either } <a name="line-240"></a> EitherTrie (trie (untrie s)) (trie (untrie t)) <a name="line-241"></a> == { trie . untrie } <a name="line-242"></a> EitherTrie s t <a name="line-243"></a>-}</span> <a name="line-244"></a> <a name="line-245"></a> <a name="line-246"></a><span class='hs-keyword'>instance</span> <span class='hs-layout'>(</span><span class='hs-conid'>HasTrie</span> <span class='hs-varid'>a</span><span class='hs-layout'>,</span> <span class='hs-conid'>HasTrie</span> <span class='hs-varid'>b</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=></span> <span class='hs-conid'>HasTrie</span> <span class='hs-layout'>(</span><span class='hs-varid'>a</span><span class='hs-layout'>,</span><span class='hs-varid'>b</span><span class='hs-layout'>)</span> <span class='hs-keyword'>where</span> <a name="line-247"></a> <span class='hs-keyword'>data</span> <span class='hs-layout'>(</span><span class='hs-varid'>a</span><span class='hs-layout'>,</span><span class='hs-varid'>b</span><span class='hs-layout'>)</span> <span class='hs-conop'>:->:</span> <span class='hs-varid'>x</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>PairTrie</span> <span class='hs-layout'>(</span><span class='hs-varid'>a</span> <span class='hs-conop'>:->:</span> <span class='hs-layout'>(</span><span class='hs-varid'>b</span> <span class='hs-conop'>:->:</span> <span class='hs-varid'>x</span><span class='hs-layout'>)</span><span class='hs-layout'>)</span> <a name="line-248"></a> <span class='hs-varid'>trie</span> <span class='hs-varid'>f</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>PairTrie</span> <span class='hs-layout'>(</span><span class='hs-varid'>trie</span> <span class='hs-layout'>(</span><span class='hs-varid'>trie</span> <span class='hs-varop'>.</span> <span class='hs-varid'>curry</span> <span class='hs-varid'>f</span><span class='hs-layout'>)</span><span class='hs-layout'>)</span> <a name="line-249"></a> <span class='hs-varid'>untrie</span> <span class='hs-layout'>(</span><span class='hs-conid'>PairTrie</span> <span class='hs-varid'>t</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>uncurry</span> <span class='hs-layout'>(</span><span class='hs-varid'>untrie</span> <span class='hs-varop'>.</span> <span class='hs-varid'>untrie</span> <span class='hs-varid'>t</span><span class='hs-layout'>)</span> <a name="line-250"></a> <span class='hs-varid'>enumerate</span> <span class='hs-layout'>(</span><span class='hs-conid'>PairTrie</span> <span class='hs-varid'>tt</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=</span> <a name="line-251"></a> <span class='hs-keyglyph'>[</span> <span class='hs-layout'>(</span><span class='hs-layout'>(</span><span class='hs-varid'>a</span><span class='hs-layout'>,</span><span class='hs-varid'>b</span><span class='hs-layout'>)</span><span class='hs-layout'>,</span><span class='hs-varid'>x</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>|</span> <span class='hs-layout'>(</span><span class='hs-varid'>a</span><span class='hs-layout'>,</span><span class='hs-varid'>t</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'><-</span> <span class='hs-varid'>enumerate</span> <span class='hs-varid'>tt</span> <span class='hs-layout'>,</span> <span class='hs-layout'>(</span><span class='hs-varid'>b</span><span class='hs-layout'>,</span><span class='hs-varid'>x</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'><-</span> <span class='hs-varid'>enumerate</span> <span class='hs-varid'>t</span> <span class='hs-keyglyph'>]</span> <a name="line-252"></a> <a name="line-253"></a><span class='hs-comment'>{- <a name="line-254"></a> untrie (trie f) <a name="line-255"></a> == { trie def } <a name="line-256"></a> untrie (PairTrie (trie (trie . curry f))) <a name="line-257"></a> == { untrie def } <a name="line-258"></a> uncurry (untrie . untrie (trie (trie . curry f))) <a name="line-259"></a> == { untrie . trie } <a name="line-260"></a> uncurry (untrie . trie . curry f) <a name="line-261"></a> == { untrie . untrie } <a name="line-262"></a> uncurry (curry f) <a name="line-263"></a> == { uncurry . curry } <a name="line-264"></a> f <a name="line-265"></a> <a name="line-266"></a> trie (untrie (PairTrie t)) <a name="line-267"></a> == { untrie def } <a name="line-268"></a> trie (uncurry (untrie . untrie t)) <a name="line-269"></a> == { trie def } <a name="line-270"></a> PairTrie (trie (trie . curry (uncurry (untrie . untrie t)))) <a name="line-271"></a> == { curry . uncurry } <a name="line-272"></a> PairTrie (trie (trie . untrie . untrie t)) <a name="line-273"></a> == { trie . untrie } <a name="line-274"></a> PairTrie (trie (untrie t)) <a name="line-275"></a> == { trie . untrie } <a name="line-276"></a> PairTrie t <a name="line-277"></a>-}</span> <a name="line-278"></a> <a name="line-279"></a><span class='hs-keyword'>instance</span> <span class='hs-layout'>(</span><span class='hs-conid'>HasTrie</span> <span class='hs-varid'>a</span><span class='hs-layout'>,</span> <span class='hs-conid'>HasTrie</span> <span class='hs-varid'>b</span><span class='hs-layout'>,</span> <span class='hs-conid'>HasTrie</span> <span class='hs-varid'>c</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=></span> <span class='hs-conid'>HasTrie</span> <span class='hs-layout'>(</span><span class='hs-varid'>a</span><span class='hs-layout'>,</span><span class='hs-varid'>b</span><span class='hs-layout'>,</span><span class='hs-varid'>c</span><span class='hs-layout'>)</span> <span class='hs-keyword'>where</span> <a name="line-280"></a> <span class='hs-keyword'>data</span> <span class='hs-layout'>(</span><span class='hs-varid'>a</span><span class='hs-layout'>,</span><span class='hs-varid'>b</span><span class='hs-layout'>,</span><span class='hs-varid'>c</span><span class='hs-layout'>)</span> <span class='hs-conop'>:->:</span> <span class='hs-varid'>x</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>TripleTrie</span> <span class='hs-layout'>(</span><span class='hs-layout'>(</span><span class='hs-layout'>(</span><span class='hs-varid'>a</span><span class='hs-layout'>,</span><span class='hs-varid'>b</span><span class='hs-layout'>)</span><span class='hs-layout'>,</span><span class='hs-varid'>c</span><span class='hs-layout'>)</span> <span class='hs-conop'>:->:</span> <span class='hs-varid'>x</span><span class='hs-layout'>)</span> <a name="line-281"></a> <span class='hs-varid'>trie</span> <span class='hs-varid'>f</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>TripleTrie</span> <span class='hs-layout'>(</span><span class='hs-varid'>trie</span> <span class='hs-layout'>(</span><span class='hs-varid'>f</span> <span class='hs-varop'>.</span> <span class='hs-varid'>trip</span><span class='hs-layout'>)</span><span class='hs-layout'>)</span> <a name="line-282"></a> <span class='hs-varid'>untrie</span> <span class='hs-layout'>(</span><span class='hs-conid'>TripleTrie</span> <span class='hs-varid'>t</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>untrie</span> <span class='hs-varid'>t</span> <span class='hs-varop'>.</span> <span class='hs-varid'>detrip</span> <a name="line-283"></a> <span class='hs-varid'>enumerate</span> <span class='hs-layout'>(</span><span class='hs-conid'>TripleTrie</span> <span class='hs-varid'>t</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>enum'</span> <span class='hs-varid'>trip</span> <span class='hs-varid'>t</span> <a name="line-284"></a> <a name="line-285"></a><a name="trip"></a><span class='hs-definition'>trip</span> <span class='hs-keyglyph'>::</span> <span class='hs-layout'>(</span><span class='hs-layout'>(</span><span class='hs-varid'>a</span><span class='hs-layout'>,</span><span class='hs-varid'>b</span><span class='hs-layout'>)</span><span class='hs-layout'>,</span><span class='hs-varid'>c</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>-></span> <span class='hs-layout'>(</span><span class='hs-varid'>a</span><span class='hs-layout'>,</span><span class='hs-varid'>b</span><span class='hs-layout'>,</span><span class='hs-varid'>c</span><span class='hs-layout'>)</span> <a name="line-286"></a><span class='hs-definition'>trip</span> <span class='hs-layout'>(</span><span class='hs-layout'>(</span><span class='hs-varid'>a</span><span class='hs-layout'>,</span><span class='hs-varid'>b</span><span class='hs-layout'>)</span><span class='hs-layout'>,</span><span class='hs-varid'>c</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=</span> <span class='hs-layout'>(</span><span class='hs-varid'>a</span><span class='hs-layout'>,</span><span class='hs-varid'>b</span><span class='hs-layout'>,</span><span class='hs-varid'>c</span><span class='hs-layout'>)</span> <a name="line-287"></a> <a name="line-288"></a><a name="detrip"></a><span class='hs-definition'>detrip</span> <span class='hs-keyglyph'>::</span> <span class='hs-layout'>(</span><span class='hs-varid'>a</span><span class='hs-layout'>,</span><span class='hs-varid'>b</span><span class='hs-layout'>,</span><span class='hs-varid'>c</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>-></span> <span class='hs-layout'>(</span><span class='hs-layout'>(</span><span class='hs-varid'>a</span><span class='hs-layout'>,</span><span class='hs-varid'>b</span><span class='hs-layout'>)</span><span class='hs-layout'>,</span><span class='hs-varid'>c</span><span class='hs-layout'>)</span> <a name="line-289"></a><span class='hs-definition'>detrip</span> <span class='hs-layout'>(</span><span class='hs-varid'>a</span><span class='hs-layout'>,</span><span class='hs-varid'>b</span><span class='hs-layout'>,</span><span class='hs-varid'>c</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=</span> <span class='hs-layout'>(</span><span class='hs-layout'>(</span><span class='hs-varid'>a</span><span class='hs-layout'>,</span><span class='hs-varid'>b</span><span class='hs-layout'>)</span><span class='hs-layout'>,</span><span class='hs-varid'>c</span><span class='hs-layout'>)</span> <a name="line-290"></a> <a name="line-291"></a> <a name="line-292"></a><span class='hs-keyword'>instance</span> <span class='hs-conid'>HasTrie</span> <span class='hs-varid'>x</span> <span class='hs-keyglyph'>=></span> <span class='hs-conid'>HasTrie</span> <span class='hs-keyglyph'>[</span><span class='hs-varid'>x</span><span class='hs-keyglyph'>]</span> <span class='hs-keyword'>where</span> <a name="line-293"></a> <span class='hs-keyword'>data</span> <span class='hs-keyglyph'>[</span><span class='hs-varid'>x</span><span class='hs-keyglyph'>]</span> <span class='hs-conop'>:->:</span> <span class='hs-varid'>a</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>ListTrie</span> <span class='hs-layout'>(</span><span class='hs-conid'>Either</span> <span class='hs-conid'>()</span> <span class='hs-layout'>(</span><span class='hs-varid'>x</span><span class='hs-layout'>,</span><span class='hs-keyglyph'>[</span><span class='hs-varid'>x</span><span class='hs-keyglyph'>]</span><span class='hs-layout'>)</span> <span class='hs-conop'>:->:</span> <span class='hs-varid'>a</span><span class='hs-layout'>)</span> <a name="line-294"></a> <span class='hs-varid'>trie</span> <span class='hs-varid'>f</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>ListTrie</span> <span class='hs-layout'>(</span><span class='hs-varid'>trie</span> <span class='hs-layout'>(</span><span class='hs-varid'>f</span> <span class='hs-varop'>.</span> <span class='hs-varid'>list</span><span class='hs-layout'>)</span><span class='hs-layout'>)</span> <a name="line-295"></a> <span class='hs-varid'>untrie</span> <span class='hs-layout'>(</span><span class='hs-conid'>ListTrie</span> <span class='hs-varid'>t</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>untrie</span> <span class='hs-varid'>t</span> <span class='hs-varop'>.</span> <span class='hs-varid'>delist</span> <a name="line-296"></a> <span class='hs-varid'>enumerate</span> <span class='hs-layout'>(</span><span class='hs-conid'>ListTrie</span> <span class='hs-varid'>t</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>enum'</span> <span class='hs-varid'>list</span> <span class='hs-varid'>t</span> <a name="line-297"></a> <a name="line-298"></a><a name="list"></a><span class='hs-definition'>list</span> <span class='hs-keyglyph'>::</span> <span class='hs-conid'>Either</span> <span class='hs-conid'>()</span> <span class='hs-layout'>(</span><span class='hs-varid'>x</span><span class='hs-layout'>,</span><span class='hs-keyglyph'>[</span><span class='hs-varid'>x</span><span class='hs-keyglyph'>]</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>-></span> <span class='hs-keyglyph'>[</span><span class='hs-varid'>x</span><span class='hs-keyglyph'>]</span> <a name="line-299"></a><span class='hs-definition'>list</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>either</span> <span class='hs-layout'>(</span><span class='hs-varid'>const</span> <span class='hs-conid'>[]</span><span class='hs-layout'>)</span> <span class='hs-layout'>(</span><span class='hs-varid'>uncurry</span> <span class='hs-layout'>(</span><span class='hs-conop'>:</span><span class='hs-layout'>)</span><span class='hs-layout'>)</span> <a name="line-300"></a> <a name="line-301"></a><a name="delist"></a><span class='hs-definition'>delist</span> <span class='hs-keyglyph'>::</span> <span class='hs-keyglyph'>[</span><span class='hs-varid'>x</span><span class='hs-keyglyph'>]</span> <span class='hs-keyglyph'>-></span> <span class='hs-conid'>Either</span> <span class='hs-conid'>()</span> <span class='hs-layout'>(</span><span class='hs-varid'>x</span><span class='hs-layout'>,</span><span class='hs-keyglyph'>[</span><span class='hs-varid'>x</span><span class='hs-keyglyph'>]</span><span class='hs-layout'>)</span> <a name="line-302"></a><span class='hs-definition'>delist</span> <span class='hs-conid'>[]</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>Left</span> <span class='hs-conid'>()</span> <a name="line-303"></a><span class='hs-definition'>delist</span> <span class='hs-layout'>(</span><span class='hs-varid'>x</span><span class='hs-conop'>:</span><span class='hs-varid'>xs</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>Right</span> <span class='hs-layout'>(</span><span class='hs-varid'>x</span><span class='hs-layout'>,</span><span class='hs-varid'>xs</span><span class='hs-layout'>)</span> <a name="line-304"></a> <a name="line-305"></a><span class='hs-cpp'>#define WordInstance(Type,TrieType)\</span> <a name="line-306"></a><span class='hs-keyword'>instance</span> <span class='hs-conid'>HasTrie</span> <span class='hs-conid'>Type</span> <span class='hs-keyword'>where</span> <span class='hs-keyglyph'>\</span> <a name="line-307"></a> <span class='hs-keyword'>data</span> <span class='hs-conid'>Type</span> <span class='hs-conop'>:->:</span> <span class='hs-varid'>a</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>TrieType</span> <span class='hs-layout'>(</span><span class='hs-keyglyph'>[</span><span class='hs-conid'>Bool</span><span class='hs-keyglyph'>]</span> <span class='hs-conop'>:->:</span> <span class='hs-varid'>a</span><span class='hs-layout'>)</span><span class='hs-layout'>;</span><span class='hs-keyglyph'>\</span> <a name="line-308"></a> <span class='hs-varid'>trie</span> <span class='hs-varid'>f</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>TrieType</span> <span class='hs-layout'>(</span><span class='hs-varid'>trie</span> <span class='hs-layout'>(</span><span class='hs-varid'>f</span> <span class='hs-varop'>.</span> <span class='hs-varid'>unbits</span><span class='hs-layout'>)</span><span class='hs-layout'>)</span><span class='hs-layout'>;</span><span class='hs-keyglyph'>\</span> <a name="line-309"></a> <span class='hs-varid'>untrie</span> <span class='hs-layout'>(</span><span class='hs-conid'>TrieType</span> <span class='hs-varid'>t</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>untrie</span> <span class='hs-varid'>t</span> <span class='hs-varop'>.</span> <span class='hs-varid'>bits</span><span class='hs-layout'>;</span><span class='hs-keyglyph'>\</span> <a name="line-310"></a> <span class='hs-varid'>enumerate</span> <span class='hs-layout'>(</span><span class='hs-conid'>TrieType</span> <span class='hs-varid'>t</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>enum'</span> <span class='hs-varid'>unbits</span> <span class='hs-varid'>t</span> <a name="line-311"></a> <a name="line-312"></a><span class='hs-conid'>WordInstance</span><span class='hs-layout'>(</span><span class='hs-conid'>Word</span><span class='hs-layout'>,</span><span class='hs-conid'>WordTrie</span><span class='hs-layout'>)</span> <a name="line-313"></a><span class='hs-conid'>WordInstance</span><span class='hs-layout'>(</span><span class='hs-conid'>Word8</span><span class='hs-layout'>,</span><span class='hs-conid'>Word8Trie</span><span class='hs-layout'>)</span> <a name="line-314"></a><span class='hs-conid'>WordInstance</span><span class='hs-layout'>(</span><span class='hs-conid'>Word16</span><span class='hs-layout'>,</span><span class='hs-conid'>Word16Trie</span><span class='hs-layout'>)</span> <a name="line-315"></a><span class='hs-conid'>WordInstance</span><span class='hs-layout'>(</span><span class='hs-conid'>Word32</span><span class='hs-layout'>,</span><span class='hs-conid'>Word32Trie</span><span class='hs-layout'>)</span> <a name="line-316"></a><span class='hs-conid'>WordInstance</span><span class='hs-layout'>(</span><span class='hs-conid'>Word64</span><span class='hs-layout'>,</span><span class='hs-conid'>Word64Trie</span><span class='hs-layout'>)</span> <a name="line-317"></a> <a name="line-318"></a><span class='hs-comment'>-- instance HasTrie Word where</span> <a name="line-319"></a><span class='hs-comment'>-- data Word :->: a = WordTrie ([Bool] :->: a)</span> <a name="line-320"></a><span class='hs-comment'>-- trie f = WordTrie (trie (f . unbits))</span> <a name="line-321"></a><span class='hs-comment'>-- untrie (WordTrie t) = untrie t . bits</span> <a name="line-322"></a><span class='hs-comment'>-- enumerate (WordTrie t) = enum' unbits t</span> <a name="line-323"></a> <a name="line-324"></a> <a name="line-325"></a><a name="bits"></a><span class='hs-comment'>-- | Extract bits in little-endian order</span> <a name="line-326"></a><span class='hs-definition'>bits</span> <span class='hs-keyglyph'>::</span> <span class='hs-conid'>Bits</span> <span class='hs-varid'>t</span> <span class='hs-keyglyph'>=></span> <span class='hs-varid'>t</span> <span class='hs-keyglyph'>-></span> <span class='hs-keyglyph'>[</span><span class='hs-conid'>Bool</span><span class='hs-keyglyph'>]</span> <a name="line-327"></a><span class='hs-definition'>bits</span> <span class='hs-num'>0</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>[]</span> <a name="line-328"></a><span class='hs-definition'>bits</span> <span class='hs-varid'>x</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>testBit</span> <span class='hs-varid'>x</span> <span class='hs-num'>0</span> <span class='hs-conop'>:</span> <span class='hs-varid'>bits</span> <span class='hs-layout'>(</span><span class='hs-varid'>shiftR</span> <span class='hs-varid'>x</span> <span class='hs-num'>1</span><span class='hs-layout'>)</span> <a name="line-329"></a> <a name="line-330"></a><a name="unbit"></a><span class='hs-comment'>-- | Convert boolean to 0 (False) or 1 (True)</span> <a name="line-331"></a><span class='hs-definition'>unbit</span> <span class='hs-keyglyph'>::</span> <span class='hs-conid'>Num</span> <span class='hs-varid'>t</span> <span class='hs-keyglyph'>=></span> <span class='hs-conid'>Bool</span> <span class='hs-keyglyph'>-></span> <span class='hs-varid'>t</span> <a name="line-332"></a><span class='hs-definition'>unbit</span> <span class='hs-conid'>False</span> <span class='hs-keyglyph'>=</span> <span class='hs-num'>0</span> <a name="line-333"></a><span class='hs-definition'>unbit</span> <span class='hs-conid'>True</span> <span class='hs-keyglyph'>=</span> <span class='hs-num'>1</span> <a name="line-334"></a> <a name="line-335"></a><a name="unbits"></a><span class='hs-comment'>-- | Bit list to value</span> <a name="line-336"></a><span class='hs-definition'>unbits</span> <span class='hs-keyglyph'>::</span> <span class='hs-conid'>Bits</span> <span class='hs-varid'>t</span> <span class='hs-keyglyph'>=></span> <span class='hs-keyglyph'>[</span><span class='hs-conid'>Bool</span><span class='hs-keyglyph'>]</span> <span class='hs-keyglyph'>-></span> <span class='hs-varid'>t</span> <a name="line-337"></a><span class='hs-definition'>unbits</span> <span class='hs-conid'>[]</span> <span class='hs-keyglyph'>=</span> <span class='hs-num'>0</span> <a name="line-338"></a><span class='hs-definition'>unbits</span> <span class='hs-layout'>(</span><span class='hs-varid'>x</span><span class='hs-conop'>:</span><span class='hs-varid'>xs</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>unbit</span> <span class='hs-varid'>x</span> <span class='hs-varop'>.|.</span> <span class='hs-varid'>shiftL</span> <span class='hs-layout'>(</span><span class='hs-varid'>unbits</span> <span class='hs-varid'>xs</span><span class='hs-layout'>)</span> <span class='hs-num'>1</span> <a name="line-339"></a> <a name="line-340"></a><span class='hs-keyword'>instance</span> <span class='hs-conid'>HasTrie</span> <span class='hs-conid'>Char</span> <span class='hs-keyword'>where</span> <a name="line-341"></a> <span class='hs-keyword'>data</span> <span class='hs-conid'>Char</span> <span class='hs-conop'>:->:</span> <span class='hs-varid'>a</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>CharTrie</span> <span class='hs-layout'>(</span><span class='hs-conid'>Int</span> <span class='hs-conop'>:->:</span> <span class='hs-varid'>a</span><span class='hs-layout'>)</span> <a name="line-342"></a> <span class='hs-varid'>untrie</span> <span class='hs-layout'>(</span><span class='hs-conid'>CharTrie</span> <span class='hs-varid'>t</span><span class='hs-layout'>)</span> <span class='hs-varid'>n</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>untrie</span> <span class='hs-varid'>t</span> <span class='hs-layout'>(</span><span class='hs-varid'>fromEnum</span> <span class='hs-varid'>n</span><span class='hs-layout'>)</span> <a name="line-343"></a> <span class='hs-varid'>trie</span> <span class='hs-varid'>f</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>CharTrie</span> <span class='hs-layout'>(</span><span class='hs-varid'>trie</span> <span class='hs-layout'>(</span><span class='hs-varid'>f</span> <span class='hs-varop'>.</span> <span class='hs-varid'>toEnum</span><span class='hs-layout'>)</span><span class='hs-layout'>)</span> <a name="line-344"></a> <span class='hs-varid'>enumerate</span> <span class='hs-layout'>(</span><span class='hs-conid'>CharTrie</span> <span class='hs-varid'>t</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>enum'</span> <span class='hs-varid'>toEnum</span> <span class='hs-varid'>t</span> <a name="line-345"></a> <a name="line-346"></a><span class='hs-comment'>-- Although Int is a Bits instance, we can't use bits directly for</span> <a name="line-347"></a><span class='hs-comment'>-- memoizing, because the "bits" function gives an infinite result, since</span> <a name="line-348"></a><span class='hs-comment'>-- shiftR (-1) 1 == -1. Instead, convert between Int and Word, and use</span> <a name="line-349"></a><span class='hs-comment'>-- a Word trie. Any Integral type can be handled similarly.</span> <a name="line-350"></a> <a name="line-351"></a><span class='hs-cpp'>#define IntInstance(IntType,WordType,TrieType) \</span> <a name="line-352"></a><span class='hs-keyword'>instance</span> <span class='hs-conid'>HasTrie</span> <span class='hs-conid'>IntType</span> <span class='hs-keyword'>where</span> <span class='hs-keyglyph'>\</span> <a name="line-353"></a> <span class='hs-keyword'>data</span> <span class='hs-conid'>IntType</span> <span class='hs-conop'>:->:</span> <span class='hs-varid'>a</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>TrieType</span> <span class='hs-layout'>(</span><span class='hs-conid'>WordType</span> <span class='hs-conop'>:->:</span> <span class='hs-varid'>a</span><span class='hs-layout'>)</span><span class='hs-layout'>;</span> <span class='hs-keyglyph'>\</span> <a name="line-354"></a> <span class='hs-varid'>untrie</span> <span class='hs-layout'>(</span><span class='hs-conid'>TrieType</span> <span class='hs-varid'>t</span><span class='hs-layout'>)</span> <span class='hs-varid'>n</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>untrie</span> <span class='hs-varid'>t</span> <span class='hs-layout'>(</span><span class='hs-varid'>fromIntegral</span> <span class='hs-varid'>n</span><span class='hs-layout'>)</span><span class='hs-layout'>;</span> <span class='hs-keyglyph'>\</span> <a name="line-355"></a> <span class='hs-varid'>trie</span> <span class='hs-varid'>f</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>TrieType</span> <span class='hs-layout'>(</span><span class='hs-varid'>trie</span> <span class='hs-layout'>(</span><span class='hs-varid'>f</span> <span class='hs-varop'>.</span> <span class='hs-varid'>fromIntegral</span><span class='hs-layout'>)</span><span class='hs-layout'>)</span><span class='hs-layout'>;</span> <span class='hs-keyglyph'>\</span> <a name="line-356"></a> <span class='hs-varid'>enumerate</span> <span class='hs-layout'>(</span><span class='hs-conid'>TrieType</span> <span class='hs-varid'>t</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>enum'</span> <span class='hs-varid'>fromIntegral</span> <span class='hs-varid'>t</span> <a name="line-357"></a> <a name="line-358"></a><span class='hs-conid'>IntInstance</span><span class='hs-layout'>(</span><span class='hs-conid'>Int</span><span class='hs-layout'>,</span><span class='hs-conid'>Word</span><span class='hs-layout'>,</span><span class='hs-conid'>IntTrie</span><span class='hs-layout'>)</span> <a name="line-359"></a><span class='hs-conid'>IntInstance</span><span class='hs-layout'>(</span><span class='hs-conid'>Int8</span><span class='hs-layout'>,</span><span class='hs-conid'>Word8</span><span class='hs-layout'>,</span><span class='hs-conid'>Int8Trie</span><span class='hs-layout'>)</span> <a name="line-360"></a><span class='hs-conid'>IntInstance</span><span class='hs-layout'>(</span><span class='hs-conid'>Int16</span><span class='hs-layout'>,</span><span class='hs-conid'>Word16</span><span class='hs-layout'>,</span><span class='hs-conid'>Int16Trie</span><span class='hs-layout'>)</span> <a name="line-361"></a><span class='hs-conid'>IntInstance</span><span class='hs-layout'>(</span><span class='hs-conid'>Int32</span><span class='hs-layout'>,</span><span class='hs-conid'>Word32</span><span class='hs-layout'>,</span><span class='hs-conid'>Int32Trie</span><span class='hs-layout'>)</span> <a name="line-362"></a><span class='hs-conid'>IntInstance</span><span class='hs-layout'>(</span><span class='hs-conid'>Int64</span><span class='hs-layout'>,</span><span class='hs-conid'>Word64</span><span class='hs-layout'>,</span><span class='hs-conid'>Int64Trie</span><span class='hs-layout'>)</span> <a name="line-363"></a> <a name="line-364"></a><span class='hs-comment'>-- For unbounded integers, we don't have a corresponding Word type, so</span> <a name="line-365"></a><span class='hs-comment'>-- extract the sign bit.</span> <a name="line-366"></a> <a name="line-367"></a><span class='hs-keyword'>instance</span> <span class='hs-conid'>HasTrie</span> <span class='hs-conid'>Integer</span> <span class='hs-keyword'>where</span> <a name="line-368"></a> <span class='hs-keyword'>data</span> <span class='hs-conid'>Integer</span> <span class='hs-conop'>:->:</span> <span class='hs-varid'>a</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>IntegerTrie</span> <span class='hs-layout'>(</span><span class='hs-layout'>(</span><span class='hs-conid'>Bool</span><span class='hs-layout'>,</span><span class='hs-keyglyph'>[</span><span class='hs-conid'>Bool</span><span class='hs-keyglyph'>]</span><span class='hs-layout'>)</span> <span class='hs-conop'>:->:</span> <span class='hs-varid'>a</span><span class='hs-layout'>)</span> <a name="line-369"></a> <span class='hs-varid'>trie</span> <span class='hs-varid'>f</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>IntegerTrie</span> <span class='hs-layout'>(</span><span class='hs-varid'>trie</span> <span class='hs-layout'>(</span><span class='hs-varid'>f</span> <span class='hs-varop'>.</span> <span class='hs-varid'>unbitsZ</span><span class='hs-layout'>)</span><span class='hs-layout'>)</span> <a name="line-370"></a> <span class='hs-varid'>untrie</span> <span class='hs-layout'>(</span><span class='hs-conid'>IntegerTrie</span> <span class='hs-varid'>t</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>untrie</span> <span class='hs-varid'>t</span> <span class='hs-varop'>.</span> <span class='hs-varid'>bitsZ</span> <a name="line-371"></a> <span class='hs-varid'>enumerate</span> <span class='hs-layout'>(</span><span class='hs-conid'>IntegerTrie</span> <span class='hs-varid'>t</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>enum'</span> <span class='hs-varid'>unbitsZ</span> <span class='hs-varid'>t</span> <a name="line-372"></a> <a name="line-373"></a> <a name="line-374"></a><a name="unbitsZ"></a><span class='hs-definition'>unbitsZ</span> <span class='hs-keyglyph'>::</span> <span class='hs-layout'>(</span><span class='hs-conid'>Bits</span> <span class='hs-varid'>n</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=></span> <span class='hs-layout'>(</span><span class='hs-conid'>Bool</span><span class='hs-layout'>,</span><span class='hs-keyglyph'>[</span><span class='hs-conid'>Bool</span><span class='hs-keyglyph'>]</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>-></span> <span class='hs-varid'>n</span> <a name="line-375"></a><span class='hs-definition'>unbitsZ</span> <span class='hs-layout'>(</span><span class='hs-varid'>positive</span><span class='hs-layout'>,</span><span class='hs-varid'>bs</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>sig</span> <span class='hs-layout'>(</span><span class='hs-varid'>unbits</span> <span class='hs-varid'>bs</span><span class='hs-layout'>)</span> <a name="line-376"></a> <span class='hs-keyword'>where</span> <a name="line-377"></a> <span class='hs-varid'>sig</span> <span class='hs-keyglyph'>|</span> <span class='hs-varid'>positive</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>id</span> <a name="line-378"></a> <span class='hs-keyglyph'>|</span> <span class='hs-varid'>otherwise</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>negate</span> <a name="line-379"></a> <a name="line-380"></a><a name="bitsZ"></a><span class='hs-definition'>bitsZ</span> <span class='hs-keyglyph'>::</span> <span class='hs-layout'>(</span><span class='hs-conid'>Ord</span> <span class='hs-varid'>n</span><span class='hs-layout'>,</span> <span class='hs-conid'>Bits</span> <span class='hs-varid'>n</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=></span> <span class='hs-varid'>n</span> <span class='hs-keyglyph'>-></span> <span class='hs-layout'>(</span><span class='hs-conid'>Bool</span><span class='hs-layout'>,</span><span class='hs-keyglyph'>[</span><span class='hs-conid'>Bool</span><span class='hs-keyglyph'>]</span><span class='hs-layout'>)</span> <a name="line-381"></a><span class='hs-definition'>bitsZ</span> <span class='hs-keyglyph'>=</span> <span class='hs-layout'>(</span><span class='hs-varop'>>=</span> <span class='hs-num'>0</span><span class='hs-layout'>)</span> <span class='hs-varop'>&&&</span> <span class='hs-layout'>(</span><span class='hs-varid'>bits</span> <span class='hs-varop'>.</span> <span class='hs-varid'>abs</span><span class='hs-layout'>)</span> <a name="line-382"></a> <a name="line-383"></a><span class='hs-comment'>-- bitsZ n = (sign n, bits (abs n))</span> <a name="line-384"></a> <a name="line-385"></a> <a name="line-386"></a> <a name="line-387"></a><span class='hs-comment'>-- TODO: make these definitions more systematic.</span> <a name="line-388"></a> <a name="line-389"></a> <a name="line-390"></a><span class='hs-comment'>---- Instances</span> <a name="line-391"></a> <a name="line-392"></a><span class='hs-comment'>{- <a name="line-393"></a> <a name="line-394"></a>The \"semantic function\" 'untrie' is a morphism over 'Monoid', 'Functor', <a name="line-395"></a>'Applicative', 'Monad', 'Category', and 'Arrow', i.e., <a name="line-396"></a> <a name="line-397"></a> untrie mempty == mempty <a name="line-398"></a> untrie (s `mappend` t) == untrie s `mappend` untrie t <a name="line-399"></a> <a name="line-400"></a> untrie (fmap f t) == fmap f (untrie t) <a name="line-401"></a> <a name="line-402"></a> untrie (pure a) == pure a <a name="line-403"></a> untrie (tf <*> tx) == untrie tf <*> untrie tx <a name="line-404"></a> <a name="line-405"></a> untrie (return a) == return a <a name="line-406"></a> untrie (u >>= k) == untrie u >>= untrie . k <a name="line-407"></a> <a name="line-408"></a> untrie id == id <a name="line-409"></a> untrie (s . t) == untrie s . untrie t <a name="line-410"></a> <a name="line-411"></a> untrie (arr f) == arr f <a name="line-412"></a> untrie (first t) == first (untrie t) <a name="line-413"></a> <a name="line-414"></a>These morphism properties imply that all of the expected laws hold, <a name="line-415"></a>assuming that we interpret equality semantically (or observationally). <a name="line-416"></a>For instance, <a name="line-417"></a> <a name="line-418"></a> untrie (mempty `mappend` a) <a name="line-419"></a> == untrie mempty `mappend` untrie a <a name="line-420"></a> == mempty `mappend` untrie a <a name="line-421"></a> == untrie a <a name="line-422"></a> <a name="line-423"></a> untrie (fmap f (fmap g a)) <a name="line-424"></a> == fmap f (untrie (fmap g a)) <a name="line-425"></a> == fmap f (fmap g (untrie a)) <a name="line-426"></a> == fmap (f.g) (untrie a) <a name="line-427"></a> == untrie (fmap (f.g) a) <a name="line-428"></a> <a name="line-429"></a>The implementation instances then follow from applying 'trie' to both <a name="line-430"></a>sides of each of these morphism laws. <a name="line-431"></a> <a name="line-432"></a>-}</span> <a name="line-433"></a> <a name="line-434"></a><span class='hs-comment'>{- <a name="line-435"></a>instance (HasTrie a, Monoid b) => Monoid (a :->: b) where <a name="line-436"></a> mempty = trie mempty <a name="line-437"></a> s `mappend` t = trie (untrie s `mappend` untrie t) <a name="line-438"></a> <a name="line-439"></a>instance HasTrie a => Functor ((:->:) a) where <a name="line-440"></a> fmap f t = trie (fmap f (untrie t)) <a name="line-441"></a> <a name="line-442"></a>instance HasTrie a => Applicative ((:->:) a) where <a name="line-443"></a> pure b = trie (pure b) <a name="line-444"></a> tf <*> tx = trie (untrie tf <*> untrie tx) <a name="line-445"></a> <a name="line-446"></a>instance HasTrie a => Monad ((:->:) a) where <a name="line-447"></a> return a = trie (return a) <a name="line-448"></a> u >>= k = trie (untrie u >>= untrie . k) <a name="line-449"></a> <a name="line-450"></a>-- instance Category (:->:) where <a name="line-451"></a>-- id = trie id <a name="line-452"></a>-- s . t = trie (untrie s . untrie t) <a name="line-453"></a> <a name="line-454"></a>-- instance Arrow (:->:) where <a name="line-455"></a>-- arr f = trie (arr f) <a name="line-456"></a>-- first t = trie (first (untrie t)) <a name="line-457"></a>-}</span> <a name="line-458"></a> <a name="line-459"></a><span class='hs-comment'>-- Simplify, using inTrie, inTrie2</span> <a name="line-460"></a> <a name="line-461"></a><span class='hs-keyword'>instance</span> <span class='hs-layout'>(</span><span class='hs-conid'>HasTrie</span> <span class='hs-varid'>a</span><span class='hs-layout'>,</span> <span class='hs-conid'>Monoid</span> <span class='hs-varid'>b</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=></span> <span class='hs-conid'>Monoid</span> <span class='hs-layout'>(</span><span class='hs-varid'>a</span> <span class='hs-conop'>:->:</span> <span class='hs-varid'>b</span><span class='hs-layout'>)</span> <span class='hs-keyword'>where</span> <a name="line-462"></a> <span class='hs-varid'>mempty</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>trie</span> <span class='hs-varid'>mempty</span> <a name="line-463"></a> <span class='hs-varid'>mappend</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>inTrie2</span> <span class='hs-varid'>mappend</span> <a name="line-464"></a> <a name="line-465"></a><span class='hs-keyword'>instance</span> <span class='hs-conid'>HasTrie</span> <span class='hs-varid'>a</span> <span class='hs-keyglyph'>=></span> <span class='hs-conid'>Functor</span> <span class='hs-layout'>(</span><span class='hs-layout'>(</span><span class='hs-conop'>:->:</span><span class='hs-layout'>)</span> <span class='hs-varid'>a</span><span class='hs-layout'>)</span> <span class='hs-keyword'>where</span> <a name="line-466"></a> <span class='hs-varid'>fmap</span> <span class='hs-varid'>f</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>inTrie</span> <span class='hs-layout'>(</span><span class='hs-varid'>fmap</span> <span class='hs-varid'>f</span><span class='hs-layout'>)</span> <a name="line-467"></a> <a name="line-468"></a><span class='hs-keyword'>instance</span> <span class='hs-conid'>HasTrie</span> <span class='hs-varid'>a</span> <span class='hs-keyglyph'>=></span> <span class='hs-conid'>Applicative</span> <span class='hs-layout'>(</span><span class='hs-layout'>(</span><span class='hs-conop'>:->:</span><span class='hs-layout'>)</span> <span class='hs-varid'>a</span><span class='hs-layout'>)</span> <span class='hs-keyword'>where</span> <a name="line-469"></a> <span class='hs-varid'>pure</span> <span class='hs-varid'>b</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>trie</span> <span class='hs-layout'>(</span><span class='hs-varid'>pure</span> <span class='hs-varid'>b</span><span class='hs-layout'>)</span> <a name="line-470"></a> <span class='hs-layout'>(</span><span class='hs-varop'><*></span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>inTrie2</span> <span class='hs-layout'>(</span><span class='hs-varop'><*></span><span class='hs-layout'>)</span> <a name="line-471"></a> <a name="line-472"></a><span class='hs-keyword'>instance</span> <span class='hs-conid'>HasTrie</span> <span class='hs-varid'>a</span> <span class='hs-keyglyph'>=></span> <span class='hs-conid'>Monad</span> <span class='hs-layout'>(</span><span class='hs-layout'>(</span><span class='hs-conop'>:->:</span><span class='hs-layout'>)</span> <span class='hs-varid'>a</span><span class='hs-layout'>)</span> <span class='hs-keyword'>where</span> <a name="line-473"></a> <span class='hs-varid'>return</span> <span class='hs-varid'>a</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>trie</span> <span class='hs-layout'>(</span><span class='hs-varid'>return</span> <span class='hs-varid'>a</span><span class='hs-layout'>)</span> <a name="line-474"></a> <span class='hs-varid'>u</span> <span class='hs-varop'>>>=</span> <span class='hs-varid'>k</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>trie</span> <span class='hs-layout'>(</span><span class='hs-varid'>untrie</span> <span class='hs-varid'>u</span> <span class='hs-varop'>>>=</span> <span class='hs-varid'>untrie</span> <span class='hs-varop'>.</span> <span class='hs-varid'>k</span><span class='hs-layout'>)</span> <a name="line-475"></a> <a name="line-476"></a><a name="idTrie"></a><span class='hs-comment'>-- | Identity trie</span> <a name="line-477"></a><span class='hs-definition'>idTrie</span> <span class='hs-keyglyph'>::</span> <span class='hs-conid'>HasTrie</span> <span class='hs-varid'>a</span> <span class='hs-keyglyph'>=></span> <span class='hs-varid'>a</span> <span class='hs-conop'>:->:</span> <span class='hs-varid'>a</span> <a name="line-478"></a><span class='hs-definition'>idTrie</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>trie</span> <span class='hs-varid'>id</span> <a name="line-479"></a> <a name="line-480"></a><span class='hs-keyword'>infixr</span> <span class='hs-num'>9</span> <span class='hs-varop'>@.@</span> <a name="line-481"></a><a name="@.@"></a><span class='hs-comment'>-- | Trie composition</span> <a name="line-482"></a><span class='hs-layout'>(</span><span class='hs-varop'>@.@</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>::</span> <span class='hs-layout'>(</span><span class='hs-conid'>HasTrie</span> <span class='hs-varid'>a</span><span class='hs-layout'>,</span> <span class='hs-conid'>HasTrie</span> <span class='hs-varid'>b</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=></span> <a name="line-483"></a> <span class='hs-layout'>(</span><span class='hs-varid'>b</span> <span class='hs-conop'>:->:</span> <span class='hs-varid'>c</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>-></span> <span class='hs-layout'>(</span><span class='hs-varid'>a</span> <span class='hs-conop'>:->:</span> <span class='hs-varid'>b</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>-></span> <span class='hs-layout'>(</span><span class='hs-varid'>a</span> <span class='hs-conop'>:->:</span> <span class='hs-varid'>c</span><span class='hs-layout'>)</span> <a name="line-484"></a><span class='hs-layout'>(</span><span class='hs-varop'>@.@</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>inTrie2</span> <span class='hs-layout'>(</span><span class='hs-varop'>.</span><span class='hs-layout'>)</span> <a name="line-485"></a> <a name="line-486"></a> <a name="line-487"></a> <a name="line-488"></a><span class='hs-comment'>-- instance Category (:->:) where</span> <a name="line-489"></a><span class='hs-comment'>-- id = idTrie</span> <a name="line-490"></a><span class='hs-comment'>-- (.) = (.:)</span> <a name="line-491"></a> <a name="line-492"></a><span class='hs-comment'>-- instance Arrow (:->:) where</span> <a name="line-493"></a><span class='hs-comment'>-- arr f = trie (arr f)</span> <a name="line-494"></a><span class='hs-comment'>-- first = inTrie first</span> <a name="line-495"></a> <a name="line-496"></a><span class='hs-comment'>{- <a name="line-497"></a> <a name="line-498"></a>Correctness of these instances follows by applying 'untrie' to each side <a name="line-499"></a>of each definition and using the property @'untrie' . 'trie' == 'id'@. <a name="line-500"></a> <a name="line-501"></a>The `Category` and `Arrow` instances don't quite work, however, because of <a name="line-502"></a>necessary but disallowed `HasTrie` constraints on the domain type. <a name="line-503"></a> <a name="line-504"></a>-}</span> <a name="line-505"></a> <a name="line-506"></a> <a name="line-507"></a><span class='hs-comment'>---- To go elsewhere</span> <a name="line-508"></a> <a name="line-509"></a><span class='hs-comment'>-- Matt Hellige's notation for @argument f . result g@.</span> <a name="line-510"></a><span class='hs-comment'>-- <<a href="http://matt.immute.net/content/pointless-fun">http://matt.immute.net/content/pointless-fun</a>></span> <a name="line-511"></a> <a name="line-512"></a><a name="~>"></a><span class='hs-layout'>(</span><span class='hs-varop'>~></span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>::</span> <span class='hs-layout'>(</span><span class='hs-varid'>a'</span> <span class='hs-keyglyph'>-></span> <span class='hs-varid'>a</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>-></span> <span class='hs-layout'>(</span><span class='hs-varid'>b</span> <span class='hs-keyglyph'>-></span> <span class='hs-varid'>b'</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>-></span> <span class='hs-layout'>(</span><span class='hs-layout'>(</span><span class='hs-varid'>a</span> <span class='hs-keyglyph'>-></span> <span class='hs-varid'>b</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>-></span> <span class='hs-layout'>(</span><span class='hs-varid'>a'</span> <span class='hs-keyglyph'>-></span> <span class='hs-varid'>b'</span><span class='hs-layout'>)</span><span class='hs-layout'>)</span> <a name="line-513"></a><a name="g"></a><span class='hs-definition'>g</span> <span class='hs-varop'>~></span> <span class='hs-varid'>f</span> <span class='hs-keyglyph'>=</span> <span class='hs-layout'>(</span><span class='hs-varid'>f</span> <span class='hs-varop'>.</span><span class='hs-layout'>)</span> <span class='hs-varop'>.</span> <span class='hs-layout'>(</span><span class='hs-varop'>.</span> <span class='hs-varid'>g</span><span class='hs-layout'>)</span> <a name="line-514"></a> <a name="line-515"></a><span class='hs-comment'>{- <a name="line-516"></a>-- Examples <a name="line-517"></a>f1,f1' :: Int -> Int <a name="line-518"></a>f1 n = n + n <a name="line-519"></a> <a name="line-520"></a>f1' = memo f1 <a name="line-521"></a>-}</span> </pre></body> </html>