<span style="font-family:courier new,monospace">I&#39;ve recently been playing with Sebastian Fischer&#39;s explicit sharing monad</span><br style="font-family:courier new,monospace"><div class="gmail_quote"><span style="font-family:courier new,monospace">library (found at <a href="http://sebfisch.github.com/explicit-sharing" target="_blank">http://sebfisch.github.com/explicit-sharing</a>) and after</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">looking at the code noticed the implementation memoizes values into an IntMap</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">of untyped values that are coerced into the correct type on retrieval, which</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">is a sensible and practical way to implement this.</span><br style="font-family:courier new,monospace"><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">Just for fun I thought I&#39;d have a go at implementing a (very impractical)</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">version without type casting but, disappointingly, I didn&#39;t quite get there.</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">I ran out of steam by the time I got around to playing with parameterized</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">monads by which stage the type signatures started looking a bit scary.</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">That and I needed to get back to my projects.</span><br style="font-family:courier new,monospace">

<br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">This has been sitting on my hard drive for a couple of weeks now and I&#39;ve</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">finally decided to clean it up and post it, maybe someone else will find it</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">amusing.</span><br style="font-family:courier new,monospace">

<br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">The post is about HList inspired type level implementation of Okasaki&#39;s</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">skew binary random access lists indexed by Roman numerals, using ideas from</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">Ralf Hinze&#39;s paper &quot;Functional Pearl: Typed Quote/Antiquote - Or: Compile-time</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">Parsing&quot; and some fun tricks from the MLton wiki:</span><br style="font-family:courier new,monospace"><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace"><a href="http://www.cs.ox.ac.uk/ralf.hinze/publications/Quote.pdf" target="_blank">http://www.cs.ox.ac.uk/ralf.hinze/publications/Quote.pdf</a></span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace"><a href="http://mlton.org/Fold" target="_blank">http://mlton.org/Fold</a></span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace"><a href="http://mlton.org/Fold01N" target="_blank">http://mlton.org/Fold01N</a></span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace"><a href="http://mlton.org/VariableArityPolymorphism" target="_blank">http://mlton.org/VariableArityPolymorphism</a></span><br style="font-family:courier new,monospace"><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">With that out of the way, we start of by declaring all the different</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">extensions we&#39;ll need.</span><br style="font-family:courier new,monospace">

<br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; {-# LANGUAGE FlexibleInstances      #-}</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; {-# LANGUAGE FunctionalDependencies #-}</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; {-# LANGUAGE MultiParamTypeClasses  #-}</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; {-# LANGUAGE ScopedTypeVariables    #-}</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; {-# LANGUAGE TypeFamilies           #-}</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; {-# LANGUAGE TypeSynonymInstances   #-}</span><br style="font-family:courier new,monospace">

<br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">These two are ugly. We need undecidable instances for bunch of things and</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">overlapping instances for the type equality trick borrowed from the HList</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">paper:</span><br style="font-family:courier new,monospace">

<br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace"><a href="http://homepages.cwi.nl/%7Eralf/HList/paper.pdf" target="_blank">http://homepages.cwi.nl/~ralf/HList/paper.pdf</a></span><br style="font-family:courier new,monospace">

<br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; {-# LANGUAGE OverlappingInstances   #-}</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; {-# LANGUAGE UndecidableInstances   #-}</span><br style="font-family:courier new,monospace">

<br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">For GHC 7 we also need to increase the context stack.</span><br style="font-family:courier new,monospace"><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; {-# OPTIONS_GHC -fcontext-stack=100 #-}</span><br style="font-family:courier new,monospace"><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">Define Boolean values at the type level.</span><br style="font-family:courier new,monospace">

<br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; data T = T</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; data F = F</span><br style="font-family:courier new,monospace">

<br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">And now Peano numbers. We don&#39;t actually use the constructors for</span><br style="font-family:courier new,monospace">
<span style="font-family:courier new,monospace">anything but if we omitted them we&#39;d have to use another extension,</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">EmptyDataDecls.</span><br style="font-family:courier new,monospace">

<br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; data Z   = Z</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; data S n = S n</span><br style="font-family:courier new,monospace">

<br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">Here we create some types for heterogeneous lists and trees. Note that Pair</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">has an extra type parameter. We provide two different versions of the cons</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">operation. One requires that extra parameter but does not require undecidable</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">instances. Unfortunately we still need undecidable instances later</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">on for indexing.</span><br style="font-family:courier new,monospace">

<br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; data Pair i x y = Pair x y   deriving Show</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; data Nil        = Nil        deriving Show</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; data Tree l x r = Node l x r deriving Show</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; data Leaf   x   = Leaf   x   deriving Show</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; type Pair&#39; x y = Pair () x y</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; nil :: Nil</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; nil = Nil</span><br style="font-family:courier new,monospace"><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">Equality, less than, addition, subtraction and multiplication by 2 type</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">functions for Peano numbers.</span><br style="font-family:courier new,monospace"><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; type family Equals m n</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; type instance Equals  Z     Z    = T</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; type instance Equals  Z    (S n) = F</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; type instance Equals (S n)  Z    = F</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; type instance Equals (S m) (S n) = Equals m n</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; type family LessThan m n</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; type instance LessThan    Z     Z  = F</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; type instance LessThan    Z  (S n) = T</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; type instance LessThan (S n)    Z  = F</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; type instance LessThan (S m) (S n) = LessThan m n</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; type family Add m n</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; type instance Add    Z     n  = n</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; type instance Add    n     Z  = n</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; type instance Add (S m) (S n) = S (S (Add m n))</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; type family Sub m n</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; type instance Sub    n     Z  = n</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; type instance Sub (S m) (S n) = Sub m n</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; type family Mul2 n</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; type instance Mul2  Z    = Z</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; type instance Mul2 (S n) = S (S (Mul2 n))</span><br style="font-family:courier new,monospace">

<br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">And finally tree depth and weight/size.</span><br style="font-family:courier new,monospace"><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; type family Depth t</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; type instance Depth (Leaf   x  ) = S  Z</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; type instance Depth (Tree l x r) = S (Depth l)</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; type family Weight t</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; type instance Weight (Leaf   x  ) = S Z</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; type instance Weight (Tree l x r) = S (Mul2 (Weight l))</span><br style="font-family:courier new,monospace"><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">For reference, here is normal implementation of random access lists</span><br style="font-family:courier new,monospace">

<br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">    newtype List a = List { unList :: [(Int, Tree a)] } deriving Show</span><br style="font-family:courier new,monospace">
<br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">    data Tree a = Leaf a</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">                | Node (Tree a) a (Tree a) deriving Show</span><br style="font-family:courier new,monospace">

<br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">    cons :: a -&gt; List a -&gt; List a</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">    cons x (List wts) = List $ case wts of</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">        (v, l) : (w, r) : wts&#39; | v == w -&gt; (1 + w + w, Node l x r) : wts&#39;</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">        _                               -&gt; (1        , Leaf   x  ) : wts</span><br style="font-family:courier new,monospace">

<br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">List here is a list of pairs of balanced binary trees and their weights.</span><br style="font-family:courier new,monospace">
<span style="font-family:courier new,monospace">The cons function has exactly two cases. The second case is trivial, we are</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">mostly interested in the first case. If the weights of the two trees at the</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">front of the list are the same, we combine them into a new tree with the newly</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">inserted element at the top.</span><br style="font-family:courier new,monospace">

<br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">Now we are ready to implement cons. This first version is simpler but requires</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">undecidable instances.</span><br style="font-family:courier new,monospace"><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; class Cons&#39; x y z | x y -&gt; z where cons&#39; :: x -&gt; y -&gt; z</span><br style="font-family:courier new,monospace">

<br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">Here we cover the cases of inserting an element into an empty list, and</span><br style="font-family:courier new,monospace">
<span style="font-family:courier new,monospace">inserting an element into a list with a single element. These cover two out of</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">four different possibilities when inserting a new element.</span><br style="font-family:courier new,monospace">

<br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; instance Cons&#39; x Nil (Pair&#39; (Leaf x) Nil) where cons&#39; = Pair . Leaf</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; instance Cons&#39; x (Pair&#39; y Nil) (Pair&#39; (Leaf x) (Pair&#39; y Nil)) where</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;     cons&#39; = Pair . Leaf</span><br style="font-family:courier new,monospace"><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">The remaining two cases occur when we have at least two elements in the list.</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">This is where we need to compare weights of trees. First observation is that</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">we don&#39;t need weight of a tree, depth is sufficient.</span><br style="font-family:courier new,monospace">

<br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">Now we have a problem. We&#39;d like to be able to write something like</span><br style="font-family:courier new,monospace">
<br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">    instance (Depth l ~ u, Depth r ~ v, Equals u v ~ T) =&gt;</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">             Cons&#39; x (Pair&#39; l (Pair&#39; r y)) (Pair&#39; (Tree l x r) y) where ...</span><br style="font-family:courier new,monospace">

<br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">    instance (Depth l ~ u, Depth r ~ v, Equals u v ~ F) =&gt;</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">             Cons&#39; x y (Pair&#39; (Leaf x) y) where ...</span><br style="font-family:courier new,monospace">

<br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">but we get a functional dependency conflict in the second instance as the type</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">variable y might stand for Pair&#39; l (Pair&#39; r y) and the functional dependency</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">already says the result should be Pair&#39; (Tree l x r) y, not</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">Pair&#39; (Leaf x) (Pair&#39; l (Pair&#39; r y))</span><br style="font-family:courier new,monospace"><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">We need to merge these two instances into one and then branch on the result of</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">the comparison of tree depths.</span><br style="font-family:courier new,monospace"><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">To do this, we introduce another type class to do the branching.</span><br style="font-family:courier new,monospace">

<br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; class ConsIf c x y z | c x y -&gt; z where consIf :: c -&gt; x -&gt; y -&gt; z</span><br style="font-family:courier new,monospace">

<br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">And merge the instances.</span><br style="font-family:courier new,monospace"><br style="font-family:courier new,monospace">
<span style="font-family:courier new,monospace">&gt; instance ( Depth l ~ u</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt;          , Depth r ~ v</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;          , Equals u v ~ c</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt;          , ConsIf c x (Pair&#39; l (Pair&#39; r y)) z ) =&gt;</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt;          Cons&#39; x (Pair&#39; l (Pair&#39; r y)) z where</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt;     cons&#39; = consIf (undefined :: c)</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; instance ConsIf F x y (Pair&#39; (Leaf x) y) where consIf _ = Pair . Leaf</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; instance (Depth l ~ u, Depth r ~ u) =&gt;</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt;          ConsIf T x (Pair&#39; l (Pair&#39; r y)) (Pair&#39; (Tree l x r) y) where</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt;     consIf _ x (Pair l (Pair r y)) = Pair (Node l x r) y</span><br style="font-family:courier new,monospace">

<br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">We can now test our cons function.</span><br style="font-family:courier new,monospace"><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; t0&#39; = cons&#39; &#39;a&#39;</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt;     $ cons&#39; (33       :: Int)</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;     $ cons&#39; (4.4      :: Float)</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt;     $ cons&#39; (88       :: Integer)</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;     $ cons&#39; ([1 .. 8] :: [Int])</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt;     $ cons&#39; &quot;moose&quot;</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;     $ cons&#39; ((6, 3)   :: (Int, Int))</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt;     $ nil</span><br style="font-family:courier new,monospace">

<br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">And ghci tells us the type is</span><br style="font-family:courier new,monospace"><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">*Main&gt; :t t0&#39;</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">t0&#39;</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">  :: Pair&#39;</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">       (Tree</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">          (Tree (Leaf Float) Int (Leaf Integer))</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">          Char</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">          (Tree (Leaf [Char]) [Int] (Leaf (Int, Int))))</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">       Nil</span><br style="font-family:courier new,monospace">

<br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">Now we get to the second version that doesn&#39;t need the undecidable instances</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">extension. In this one we go a step back and attempt to keep track of depth</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">information in the type of the list. When we again end up at the point where</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">we need to compare if two trees at the front of the list are of the same</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">depth, we run into a problem.</span><br style="font-family:courier new,monospace">

<br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">    instance Cons x (Pair i l (Pair i r y))</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">                    (Pair (S i) (Tree l x r) y) where ...</span><br style="font-family:courier new,monospace">

<br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">    instance Cons x (Pair i y (Pair j z w))</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">                    (Pair (S Z) x (Pair i y (Pair j z w))) where ...</span><br style="font-family:courier new,monospace">

<br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">This clearly won&#39;t work as we again get a functional dependency conflict. The j</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">type variable could be the same as i in which case we have two different rules</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">for what the result of consing x with (Pair i l (Pair i r y)) should be.</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">As we don&#39;t want to use undecidable instances, we are stuck. Unless we can</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">find a way to disambiguate the two instances.</span><br style="font-family:courier new,monospace">

<br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">Instead of keeping track of depth information, we could try to track how many</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">elements we need to complete a new tree. That way instead of counting up, we</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">are counting down towards zero and it becomes easy to differentiate the two</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">instances as only the one where the depths of the two trees are equal will</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">contain a Z.</span><br style="font-family:courier new,monospace">

<br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">Keeping track of how many elements are missing turns out to be a problem,</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">at least as long as we don&#39;t want to use undecidable instances. Fortunately</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">we can replace the number of elements missing with the number of levels the</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">tree at the front needs before its depth matches the tree that follows.</span><br style="font-family:courier new,monospace"><br style="font-family:courier new,monospace">
<span style="font-family:courier new,monospace">&gt; class Cons x y z | x y -&gt; z where cons :: x -&gt; y -&gt; z</span><br style="font-family:courier new,monospace"><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">Inserting an element into an empty list involves adding the element to the</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">front and setting its the depth counter to 1.</span><br style="font-family:courier new,monospace"><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; instance Cons x Nil (Pair (S Z) (Leaf x) Nil) where cons = Pair . Leaf</span><br style="font-family:courier new,monospace">

<br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">If we are inserting an element into a list that already has a single tree,</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">we again add the new element to the front, set its counter to 1 and we</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">decrement the counter of the tree that now follows the newly inserted element.</span><br style="font-family:courier new,monospace">

<br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; instance Cons x (Pair (S i) y Nil) (Pair (S Z) (Leaf x) (Pair i y Nil)) where</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;     cons x (Pair y z) = Pair (Leaf x) (Pair y z)</span><br style="font-family:courier new,monospace"><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">Here we have the case where the list already contains at least two trees but</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">their depths are not equal. Like with the previous instance we insert the new</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">element to the front and decrement the counter of the tree that now follows it.</span><br style="font-family:courier new,monospace">

<br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; instance Cons x (Pair (S i) y (Pair (S j) z w))</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt;                 (Pair (S Z) (Leaf x) (Pair i y (Pair (S j) z w))) where</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt;     cons x (Pair y z) = Pair (Leaf x) (Pair y z)</span><br style="font-family:courier new,monospace">

<br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">That means we are left with one more case to handle. The case when the depths</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">of the two trees are the same, or rather when the counter reaches 0.</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">As we merge the two trees and create a new tree, we must also decrement the</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">counter of the tree that follows. What this means is that we really need two</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">instances. One where there are only two trees of the same depth in the list,</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">and one where those two trees are followed by at least one more tree.</span><br style="font-family:courier new,monospace"><br style="font-family:courier new,monospace">
<span style="font-family:courier new,monospace">&gt; instance (Depth l ~ i, Depth r ~ i) =&gt;</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt;          Cons x (Pair i l (Pair Z r Nil)) (Pair (S i) (Tree l x r) Nil) where</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt;     cons x (Pair l (Pair r y)) = Pair (Node l x r) y</span><br style="font-family:courier new,monospace">

<br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">As we merge the trees into a new tree, we reset and increment the depth</span><br style="font-family:courier new,monospace">
<span style="font-family:courier new,monospace">counter. Note that we are using the first tree&#39;s counter. Reason for that is</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">that the counter must represent the tree&#39;s depth as the tree at the front was</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">either just inserted and so its counter is 1, or it was created when two</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">smaller trees merged and its counter was set to its depth.</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">Finally we must also decrement the counter of the tree that follows.</span><br style="font-family:courier new,monospace"><br style="font-family:courier new,monospace">
<span style="font-family:courier new,monospace">&gt; instance (Depth l ~ i, Depth r ~ i) =&gt;</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt;          Cons x (Pair i l (Pair Z r (Pair (S j) y z)))</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;                 (Pair (S i) (Tree l x r) (Pair j y z)) where</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;     cons x (Pair l (Pair r (Pair y z))) = Pair (Node l x r) (Pair y z)</span><br style="font-family:courier new,monospace"><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">Now we can test the new cons function.</span><br style="font-family:courier new,monospace"><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; t0 = cons &#39;a&#39;</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;    $ cons (33       :: Int)</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt;    $ cons (4.4      :: Float)</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;    $ cons (88       :: Integer)</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt;    $ cons ([1 .. 8] :: [Int])</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;    $ cons &quot;moose&quot;</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt;    $ cons ((6, 3)   :: (Int, Int))</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;    $ nil</span><br style="font-family:courier new,monospace"><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">The type is slightly more verbose.</span><br style="font-family:courier new,monospace">

<br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">*Main&gt; :t t0</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">t0</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">  :: Pair</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">       (S (S (S Z)))</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">       (Tree</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">          (Tree (Leaf Float) Int (Leaf Integer))</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">          Char</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">          (Tree (Leaf [Char]) [Int] (Leaf (Int, Int))))</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">       Nil</span><br style="font-family:courier new,monospace"><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">Here we introduce our wrapper for Roman numerals though we won&#39;t get to</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">play with those just yet.</span><br style="font-family:courier new,monospace"><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; newtype R n = R { unR :: Int } deriving Show</span><br style="font-family:courier new,monospace">

<br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">We want to get indexing and updates out of the way first. The reference</span><br style="font-family:courier new,monospace">
<span style="font-family:courier new,monospace">implementation for the indexing function is a bit more complex than the cons</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">function. Each of the cases we need to handle has been marked with a comment</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">so we can see which instance matches which part of the code.</span><br style="font-family:courier new,monospace"><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">    index :: List a -&gt; Int -&gt; Maybe a</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">    index (List ((w, t) : wts)) i</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">      | i &lt; w     = index&#39; w i t                    -- 1</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">      | otherwise = index (List wts) (i - w)        -- 2</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">        where</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">        index&#39; 1 0 (Leaf   x  ) = Just x            -- 3</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">        index&#39; _ _ (Leaf   _  ) = Nothing</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">        index&#39; w i (Node l x r)</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">          | i == 0    = Just x                      -- 4</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">          | i &lt;= w&#39;   = index&#39; w&#39; (i - 1     ) l    -- 5</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">          | otherwise = index&#39; w&#39; (i - 1 - w&#39;) r    -- 6</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">            where</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">            w&#39; = w `div` 2</span><br style="font-family:courier new,monospace">

<br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">    index _ _ = Nothing</span><br style="font-family:courier new,monospace"><br style="font-family:courier new,monospace">
<span style="font-family:courier new,monospace">We don&#39;t need to do anything when the index is out of range - the type system</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">takes care of that for us.</span><br style="font-family:courier new,monospace">

<br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; class Index     i x y |   i y -&gt; x where index   ::      y -&gt; R i -&gt; x</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; class IndexIf c i x y | c i y -&gt; x where indexIf :: c -&gt; y -&gt; R i -&gt; x</span><br style="font-family:courier new,monospace"><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">First we handle the easy cases.</span><br style="font-family:courier new,monospace"><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; instance Index Z x (Leaf   x  ) where index (Leaf   x  ) _ = x      -- 3</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; instance Index Z x (Tree l x r) where index (Node _ x _) _ = x      -- 4</span><br style="font-family:courier new,monospace"><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">Cases 5 and 6 require the use of a second type class so we can branch on the</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">result of the comparison i &lt;= w, though we rewrite it to w &lt; i&#39; + 1 to make</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">use of the LessThan type family and to differentiate instance 6 from</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">instance 4.</span><br style="font-family:courier new,monospace">

<br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">Instead of halving the weight of the tree we are currently working on, we</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">get the weight of one of its children.</span><br style="font-family:courier new,monospace"><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; instance ( Weight l ~ w</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;          , LessThan w (S i) ~ c</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt;          , IndexIf c i x (Tree l y r) ) =&gt; Index (S i) x (Tree l y r) where</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt;     index t _ = indexIf (undefined :: c) t (undefined :: R i)       -- 5, 6</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; instance Index i x l =&gt; IndexIf F i x (Tree l y r) where</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;     indexIf _ (Node l _ _) = index l                                -- 5</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; instance ( Weight r ~ w</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt;          , Sub i w ~ j</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;          , Index j x r ) =&gt; IndexIf T i x (Tree l y r) where</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;     indexIf _ (Node _ _ r) _ = index r (undefined :: R j)           -- 6</span><br style="font-family:courier new,monospace"><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">Cases 1 and 2 are handled in a similar way.</span><br style="font-family:courier new,monospace"><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; instance ( Weight t ~ w</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;          , LessThan i w ~ c</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt;          , IndexIf c i x (Pair j t y) ) =&gt; Index i x (Pair j t y) where</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt;     index = indexIf (undefined :: c)                                -- 1, 2</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; instance Index i x t =&gt; IndexIf T i x (Pair j t y) where</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;     indexIf _ (Pair t _) = index t                                  -- 1</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; instance ( Weight t ~ w</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt;          , Sub i w ~ j</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;          , Index j x y ) =&gt; IndexIf F i x (Pair k t y) where</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;     indexIf _ (Pair _ y) _ = index y (undefined :: R j)             -- 2</span><br style="font-family:courier new,monospace"><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">Update is similar.</span><br style="font-family:courier new,monospace"><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">    update :: Int -&gt; a -&gt; List a -&gt; List a</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">    update i x (List ((w, t) : wts)) = List $</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">        if i &lt; w then (w, update&#39; w i t) : wts                      -- 1</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">                 else (w, t) : unList (update (i - w) x (List wts)) -- 2</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">        where</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">        update&#39; 1 0 (Leaf _     ) = Leaf x                          -- 3</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">        update&#39; _ _ (Leaf _     ) = error &quot;update&quot;</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">        update&#39; w i (Node l x&#39; r)</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">          | i == 0    = Node l  x  r                                -- 4</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">          | i &lt;= w&#39;   = Node l&#39; x&#39; r                                -- 5</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">          | otherwise = Node l  x&#39; r&#39;                               -- 6</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">            where</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">            w&#39; = w `div` 2</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">            l&#39; = update&#39; w&#39; (i - 1     ) l</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">            r&#39; = update&#39; w&#39; (i - 1 - w&#39;) r</span><br style="font-family:courier new,monospace">

<br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">    update _ _ _ = error &quot;update&quot;</span><br style="font-family:courier new,monospace"><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; class Index i x z =&gt; Update i x y z | i x y -&gt; z where</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt;     update :: y -&gt; R i -&gt; x -&gt; z</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; class UpdateIf c i x y z | c i x y -&gt; z where</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;     updateIf :: c -&gt; y -&gt; R i -&gt; x -&gt; z</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; instance Update Z x (Leaf y) (Leaf x) where</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt;     update _ _ x = Leaf x                                           -- 3</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; instance Update Z x (Tree l y r) (Tree l x r) where</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;     update (Node l _ r) _ x = Node l x r                            -- 4</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; instance ( Weight l ~ w</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt;          , LessThan w (S i) ~ c</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;          , Index (S i) x t</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt;          , UpdateIf c i x (Tree l y r) t) =&gt;</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt;          Update (S i) x (Tree l y r) t where</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt;     update t _ = updateIf (undefined :: c) t (undefined :: R i)     -- 5, 6</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; instance Update i x l l&#39; =&gt; UpdateIf F i x (Tree l y r) (Tree l&#39; y r) where</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;     updateIf _ (Node l y r) i x = Node (update l i x) y r           -- 5</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; instance ( Weight r ~ w</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt;          , Sub i w ~ j</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;          , Update j x r r&#39; ) =&gt;</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;          UpdateIf T i x (Tree l y r) (Tree l y r&#39;) where</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;     updateIf _ (Node l y r) _ x =                                   -- 6</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt;         Node l y (update r (undefined :: R j) x)</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; instance ( Weight t ~ w</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;          , LessThan i w ~ c</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt;          , Index i x p</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;          , UpdateIf c i x (Pair j t y) p ) =&gt; Update i x (Pair j t y) p where</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;     update = updateIf (undefined :: c)                              -- 1, 2</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; instance Update i x t t&#39; =&gt; UpdateIf T i x (Pair j t y) (Pair j t&#39; y) where</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt;     updateIf _ (Pair t y) i x = Pair (update t i x) y               -- 1</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; instance ( Weight t ~ w</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;          , Sub i w ~ j</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt;          , Update j x y z ) =&gt; UpdateIf F i x (Pair k t y) (Pair k t z) where</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt;     updateIf _ (Pair t y) _ x =                                     -- 2</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;         Pair t (update y (undefined :: R j) x)</span><br style="font-family:courier new,monospace"><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">Maybe we could combine Update and Index type classes into a single class? But</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">we won&#39;t attempt that here.</span><br style="font-family:courier new,monospace"><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">Now that we have indexing and updates, we need values we can use to index the</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">list. Typing Z, S Z, S (S Z) and so on is too tedious and not very readable.</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">We could use templates to predefine a whole bunch of type level numbers.</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">That&#39;s kind of ugly though. And we can do it without using any extensions, in</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">plain Haskell 98.</span><br style="font-family:courier new,monospace">

<br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">We start off by making I a type synonym for S. Then we define types II to X,</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">XX to C in steps of 10, CC to M in steps of 100 and finally we define MM and</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">MMM. I don&#39;t know how Roman numerals are supposed to work above 3999 so that&#39;s</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">the largest number we will be able to encode. Probably for the best as the</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">type system doesn&#39;t seem too happy about having to deal with types of this</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">sort.</span><br style="font-family:courier new,monospace"><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; type I    n = S       n</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; type II   n = I (I    n)</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; type III  n = I (II   n)</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; type IV   n = I (III  n)</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; type V    n = I (IV   n)</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; type VI   n = I (V    n)</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; type VII  n = I (VI   n)</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; type VIII n = I (VII  n)</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; type IX   n = I (VIII n)</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; type X    n = I (IX   n)</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; type XX   n = X (X    n)</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; type XXX  n = X (XX   n)</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; type XL   n = X (XXX  n)</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; type L    n = X (XL   n)</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; type LX   n = X (L    n)</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; type LXX  n = X (LX   n)</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; type LXXX n = X (LXX  n)</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; type XC   n = X (LXXX n)</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; type C    n = X (XC   n)</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; type CC   n = C (C    n)</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; type CCC  n = C (CC   n)</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; type CD   n = C (CCC  n)</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; type D    n = C (CD   n)</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; type DC   n = C (D    n)</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; type DCC  n = C (DC   n)</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; type DCCC n = C (DCC  n)</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; type CM   n = C (DCCC n)</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; type M    n = C (CM   n)</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; type MM   n = M (M    n)</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; type MMM  n = M (MM   n)</span><br style="font-family:courier new,monospace"><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">Now for the fun part. We&#39;d like to be able to construct only valid Roman</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">numerals and that the type signatures match the values. We start of by</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">defining the return and lift functions as described in Ralf Hinze&#39;s paper.</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">We don&#39;t go all the way to creating a monad as these two functions are the</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">only thing we need.</span><br style="font-family:courier new,monospace">

<br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; ret  a f = f a</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; lift   f = ret . f</span><br style="font-family:courier new,monospace">

<br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">Now before we continue, we need a way to ensure that only valid numbers are</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">constructed. We can group numbers in the range I to X into one group, let&#39;s</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">call it ones, X to C into group tens, C to M into group hundreds and M, MM and</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">MMM are in group thousands. A valid number can have at most 1 digit from each</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">group. Digits also have to be ordered from largest to smallest, left to right.</span><br style="font-family:courier new,monospace">

<br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">To do that, we could try and reuse the LessThen type family from before and add</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">constraints so that a digit from the tens group can only be appended to a</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">number less than ten. And a digit from the hundreds group can only be applied</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">to a number less than a hundred. This approach works but it makes the GHC&#39;s</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">type system choke and evaluating types of expressions takes minutes.</span><br style="font-family:courier new,monospace">

<br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">We could also create a class for each of the groups and a set of combinators</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">that can only be applied to a group of a lower rank. This works better.</span><br style="font-family:courier new,monospace"><br style="font-family:courier new,monospace">
<span style="font-family:courier new,monospace">But we can go a step further than that - we don&#39;t actually need any type</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">classes. All we need is one more phantom type for the rank of the number.</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">So we introduce a second type that resembles R, only has one extra type</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">variable.</span><br style="font-family:courier new,monospace">

<br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; newtype R&#39; n s = R&#39; { unR&#39; :: Int } deriving Show</span><br style="font-family:courier new,monospace"><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">Here we make use of ret and lift to create polyvariadic functions for</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">constructing Roman numerals. rn starts the construction and nr finalizes it.</span><br style="font-family:courier new,monospace">

<br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; rn :: ((R&#39; n s -&gt; R n) -&gt; r) -&gt; r</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; rn f = ret (R . unR&#39;) f</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; nr :: (R&#39; Z (IV Z) -&gt; r) -&gt; r</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; nr f = f (R&#39; 0)</span><br style="font-family:courier new,monospace"><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">Trying them in ghci we get</span><br style="font-family:courier new,monospace">

<br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">*Main&gt; rn nr</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">R {unR = 0}</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">*Main&gt; :t rn nr</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">rn nr :: R Z</span><br style="font-family:courier new,monospace">

<br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">We have a zero. Notice in the type signature for nr, rank of zero is 4.</span><br style="font-family:courier new,monospace">
<br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">Now we need to generate the digits. We can use a single function to generate</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">all of them.</span><br style="font-family:courier new,monospace"><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; mkR n = lift (\f -&gt; f . R&#39; . (+ n) . unR&#39;)</span><br style="font-family:courier new,monospace">

<br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">And we encode the constraints in the type. Digits from the ones group can only</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">be applied to a number of rank 4. There is only one number of rank 4 and that</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">is zero.</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">Applying a digit from the ones group to a zero gives us a number of rank 3.</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">Digits from the tens group can be applied to numbers of ranks 3 or 4 and</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">return a number of rank 2. And so on.</span><br style="font-family:courier new,monospace"><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; type RF n m s t k r = (R&#39; n s -&gt; k) -&gt; ((R&#39; m t -&gt; k) -&gt; r) -&gt; r</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; i    :: RF (I    n) n (III Z) (IV  s) k r</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; ii   :: RF (II   n) n (III Z) (IV  s) k r</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; iii  :: RF (III  n) n (III Z) (IV  s) k r</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; iv   :: RF (IV   n) n (III Z) (IV  s) k r</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; v    :: RF (V    n) n (III Z) (IV  s) k r</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; vi   :: RF (VI   n) n (III Z) (IV  s) k r</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; vii  :: RF (VII  n) n (III Z) (IV  s) k r</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; viii :: RF (VIII n) n (III Z) (IV  s) k r</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; ix   :: RF (IX   n) n (III Z) (IV  s) k r</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; x    :: RF (X    n) n (II  Z) (III s) k r</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; xx   :: RF (XX   n) n (II  Z) (III s) k r</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; xxx  :: RF (XXX  n) n (II  Z) (III s) k r</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; xl   :: RF (XL   n) n (II  Z) (III s) k r</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; l    :: RF (L    n) n (II  Z) (III s) k r</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; lx   :: RF (LX   n) n (II  Z) (III s) k r</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; lxx  :: RF (LXX  n) n (II  Z) (III s) k r</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; lxxx :: RF (LXXX n) n (II  Z) (III s) k r</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; xc   :: RF (XC   n) n (II  Z) (III s) k r</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; c    :: RF (C    n) n (I   Z) (II  s) k r</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; cc   :: RF (CC   n) n (I   Z) (II  s) k r</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; ccc  :: RF (CCC  n) n (I   Z) (II  s) k r</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; cd   :: RF (CD   n) n (I   Z) (II  s) k r</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; d    :: RF (D    n) n (I   Z) (II  s) k r</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; dc   :: RF (DC   n) n (I   Z) (II  s) k r</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; dcc  :: RF (DCC  n) n (I   Z) (II  s) k r</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; dccc :: RF (DCCC n) n (I   Z) (II  s) k r</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; cm   :: RF (CM   n) n (I   Z) (II  s) k r</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; m    :: RF (M    n) n      Z  (I   s) k r</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; mm   :: RF (MM   n) n      Z  (I   s) k r</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; mmm  :: RF (MMM  n) n      Z  (I   s) k r</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; i    = mkR    1</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; ii   = mkR    2</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; iii  = mkR    3</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; iv   = mkR    4</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; v    = mkR    5</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; vi   = mkR    6</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; vii  = mkR    7</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; viii = mkR    8</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; ix   = mkR    9</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; x    = mkR   10</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; xx   = mkR   20</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; xxx  = mkR   30</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; xl   = mkR   40</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; l    = mkR   50</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; lx   = mkR   60</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; lxx  = mkR   70</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; lxxx = mkR   80</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; xc   = mkR   90</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; c    = mkR  100</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; cc   = mkR  200</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; ccc  = mkR  300</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; cd   = mkR  400</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; d    = mkR  500</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; dc   = mkR  600</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; dcc  = mkR  700</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; dccc = mkR  800</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; cm   = mkR  900</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; m    = mkR 1000</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; mm   = mkR 2000</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; mmm  = mkR 3000</span><br style="font-family:courier new,monospace">

<br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">We can now try to construct a number such as 2011.</span><br style="font-family:courier new,monospace"><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; r2011 = rn mm x i nr</span><br style="font-family:courier new,monospace"><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">*Main&gt; r2011</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">R {unR = 2011}</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">*Main&gt; :t r2011</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">r2011 :: R (MM (X (I Z)))</span><br style="font-family:courier new,monospace"><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">The type reflects the value we entered.</span><br style="font-family:courier new,monospace">

<br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">Attempting to construct an invalid number gives us an error</span><br style="font-family:courier new,monospace"><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">*Main&gt; rn v vi nr</span><br style="font-family:courier new,monospace"><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&lt;interactive&gt;:1:0:</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">    Couldn&#39;t match expected type `Z&#39; against inferred type `S s&#39;</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">    Probable cause: `rn&#39; is applied to too many arguments</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">    In the expression: rn v vi nr</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">    In the definition of `it&#39;: it = rn v vi nr</span><br style="font-family:courier new,monospace">

<br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">I&#39;ll finish off this post with a generic map function. Here we use the type</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">equality trick from the HList paper.</span><br style="font-family:courier new,monospace"><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; class GMap     t p q |   t p -&gt; q where gmap   ::      t -&gt; p -&gt; q</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; class GMapIf c t p q | c t p -&gt; q where gmapIf :: c -&gt; t -&gt; p -&gt; q</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; instance GMap (a -&gt; b) Nil Nil where gmap _ = id</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; instance ( TypeEq a x c</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt;          , GMapIf c (a -&gt; b) (Leaf x) (Leaf y) ) =&gt;</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;         </span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt;          GMap (a -&gt; b) (Leaf x) (Leaf y) where gmap = gmapIf (undefined :: c)</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; instance ( TypeEq a x c</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;          , GMapIf c (a -&gt; b) (Tree l x r) (Tree l&#39; y r&#39;) ) =&gt;</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;          GMap (a -&gt; b) (Tree l x r) (Tree l&#39; y r&#39;) where</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;     gmap = gmapIf (undefined :: c)</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; instance ( GMap (a -&gt; b) x y</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt;          , GMap (a -&gt; b) p q ) =&gt;</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt;          GMap (a -&gt; b) (Pair i x p) (Pair i y q) where</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt;     gmap f (Pair x p) = Pair (gmap f x) (gmap f p)</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; instance GMapIf F (a -&gt; b) (Leaf x) (Leaf x) where gmapIf _ _ = id</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; instance GMapIf T (a -&gt; b) (Leaf a) (Leaf b) where</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;     gmapIf _ f (Leaf a) = Leaf (f a)</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; instance ( GMap (a -&gt; b) l l&#39;</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt;          , GMap (a -&gt; b) r r&#39; ) =&gt;</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt;          GMapIf F (a -&gt; b) (Tree l x r) (Tree l&#39; x r&#39;) where</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt;     gmapIf _ f (Node l x r) = Node (gmap f l) x (gmap f r)</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; instance ( GMap (a -&gt; b) l l&#39;</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;          , GMap (a -&gt; b) r r&#39; ) =&gt;</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;          GMapIf T (a -&gt; b) (Tree l a r) (Tree l&#39; b r&#39;) where</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt;     gmapIf _ f (Node l a r) = Node (gmap f l) (f a) (gmap f r)</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; type family Cast     a</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; type family Cast&#39;  t a</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; type family Cast&#39;&#39; t a</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; type instance Cast      a = Cast&#39;  () a</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; type instance Cast&#39;  t  a = Cast&#39;&#39; t  a</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; type instance Cast&#39;&#39; () a = a</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; class TypeEq x y c | x y -&gt; c</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; instance Cast c ~ F =&gt; TypeEq x y c</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; instance                 TypeEq Char  Char  T</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; instance                 TypeEq Int   Int   T</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; instance                 TypeEq Float Float T</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; instance TypeEq a a T =&gt; TypeEq [a]   [a]   T</span><br style="font-family:courier new,monospace">

<br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">And a few tests to see if it all works.</span><br style="font-family:courier new,monospace"><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; t1 = gmap (length   :: String -&gt; Int) t0</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; t2 = gmap (length   :: [Int]  -&gt; Int) t1</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; t3 = gmap ((+ 1000) :: Int    -&gt; Int) t2</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; t4 = cons (t0 `index` rn iv nr) t3</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; t5 = update t4 (rn iv nr) &quot;asdf&quot;</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; t1&#39; = gmap (length   :: String -&gt; Int) t0&#39;</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt; t2&#39; = gmap (length   :: [Int]  -&gt; Int) t1&#39;</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; t3&#39; = gmap ((+ 1000) :: Int    -&gt; Int) t2&#39;</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; t4&#39; = cons&#39; (t0&#39; `index` rn iv nr) t3&#39;</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">&gt;</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">&gt; t5&#39; = update t4&#39; (rn iv nr) &quot;asdf&quot;</span><br style="font-family:courier new,monospace"><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">As a bonus the implementation of type-level Roman numerals in Standard ML.</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">SML/NJ has a fit trying to load the code. It seems to cope with it if</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">constructors for values above 100 are commented out. And it gives really nice</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">type signatures. MLton has no problems compiling the code, but fully expands</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">all type signatures.</span><br style="font-family:courier new,monospace">

<br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">(*****************************************************************************)</span><br style="font-family:courier new,monospace">

<br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">signature ROMAN = sig</span><br style="font-family:courier new,monospace"><br style="font-family:courier new,monospace">
<span style="font-family:courier new,monospace">    type z</span><br style="font-family:courier new,monospace"><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">    type &#39;n i</span><br style="font-family:courier new,monospace">

<br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">    type &#39;n ii   = &#39;n i i</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">    type &#39;n iii  = &#39;n i ii</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">    type &#39;n iv   = &#39;n i iii</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">    type &#39;n v    = &#39;n i iv</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">    type &#39;n vi   = &#39;n i v</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">    type &#39;n vii  = &#39;n i vi</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">    type &#39;n viii = &#39;n i vii</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">    type &#39;n ix   = &#39;n i viii</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">    type &#39;n x    = &#39;n i ix</span><br style="font-family:courier new,monospace"><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">    type &#39;n xx   = &#39;n x x</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">    type &#39;n xxx  = &#39;n x xx</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">    type &#39;n xl   = &#39;n x xxx</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">    type &#39;n l    = &#39;n x xl</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">    type &#39;n lx   = &#39;n x l</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">    type &#39;n lxx  = &#39;n x lx</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">    type &#39;n lxxx = &#39;n x lxx</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">    type &#39;n xc   = &#39;n x lxxx</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">    type &#39;n c    = &#39;n x xc</span><br style="font-family:courier new,monospace">

<br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">    type &#39;n cc   = &#39;n c c</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">    type &#39;n ccc  = &#39;n c cc</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">    type &#39;n cd   = &#39;n c ccc</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">    type &#39;n d    = &#39;n c cd</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">    type &#39;n dc   = &#39;n c d</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">    type &#39;n dcc  = &#39;n c dc</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">    type &#39;n dccc = &#39;n c dcc</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">    type &#39;n cm   = &#39;n c dccc</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">    type &#39;n m    = &#39;n c cm</span><br style="font-family:courier new,monospace"><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">    type &#39;n mm   = &#39;n m m</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">    type &#39;n mmm  = &#39;n m mm</span><br style="font-family:courier new,monospace"><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">    type  &#39;n      r</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">    type (&#39;n, &#39;s) r&#39;</span><br style="font-family:courier new,monospace"><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">    val toInt : &#39;n r -&gt; int</span><br style="font-family:courier new,monospace">

<br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">    val &lt;|  : (((&#39;n, &#39;s) r&#39; -&gt; &#39;n r) -&gt; &#39;r) -&gt; &#39;r</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">    val  |&gt; : ((z, z iv) r&#39; -&gt; &#39;r) -&gt; &#39;r</span><br style="font-family:courier new,monospace"><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">    type (&#39;n, &#39;m, &#39;s, &#39;t, &#39;k, &#39;r) rf =</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">        ((&#39;n, &#39;s) r&#39; -&gt; &#39;k) -&gt; (((&#39;m, &#39;t) r&#39; -&gt; &#39;k) -&gt; &#39;r) -&gt; &#39;r</span><br style="font-family:courier new,monospace">

<br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">    val i    : (&#39;n i   , &#39;n, z iii, &#39;s iv , &#39;k, &#39;r) rf</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">    val ii   : (&#39;n ii  , &#39;n, z iii, &#39;s iv , &#39;k, &#39;r) rf</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">    val iii  : (&#39;n iii , &#39;n, z iii, &#39;s iv , &#39;k, &#39;r) rf</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">    val iv   : (&#39;n iv  , &#39;n, z iii, &#39;s iv , &#39;k, &#39;r) rf</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">    val v    : (&#39;n v   , &#39;n, z iii, &#39;s iv , &#39;k, &#39;r) rf</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">    val vi   : (&#39;n vi  , &#39;n, z iii, &#39;s iv , &#39;k, &#39;r) rf</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">    val vii  : (&#39;n vii , &#39;n, z iii, &#39;s iv , &#39;k, &#39;r) rf</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">    val viii : (&#39;n viii, &#39;n, z iii, &#39;s iv , &#39;k, &#39;r) rf</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">    val ix   : (&#39;n ix  , &#39;n, z iii, &#39;s iv , &#39;k, &#39;r) rf</span><br style="font-family:courier new,monospace">

<br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">    val x    : (&#39;n x   , &#39;n, z ii , &#39;s iii, &#39;k, &#39;r) rf</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">    val xx   : (&#39;n xx  , &#39;n, z ii , &#39;s iii, &#39;k, &#39;r) rf</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">    val xxx  : (&#39;n xxx , &#39;n, z ii , &#39;s iii, &#39;k, &#39;r) rf</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">    val xl   : (&#39;n xl  , &#39;n, z ii , &#39;s iii, &#39;k, &#39;r) rf</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">    val l    : (&#39;n l   , &#39;n, z ii , &#39;s iii, &#39;k, &#39;r) rf</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">    val lx   : (&#39;n lx  , &#39;n, z ii , &#39;s iii, &#39;k, &#39;r) rf</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">    val lxx  : (&#39;n lxx , &#39;n, z ii , &#39;s iii, &#39;k, &#39;r) rf</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">    val lxxx : (&#39;n lxxx, &#39;n, z ii , &#39;s iii, &#39;k, &#39;r) rf</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">    val xc   : (&#39;n xc  , &#39;n, z ii , &#39;s iii, &#39;k, &#39;r) rf</span><br style="font-family:courier new,monospace">

<br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">    val c    : (&#39;n c   , &#39;n, z i  , &#39;s ii , &#39;k, &#39;r) rf</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">    val cc   : (&#39;n cc  , &#39;n, z i  , &#39;s ii , &#39;k, &#39;r) rf</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">    val ccc  : (&#39;n ccc , &#39;n, z i  , &#39;s ii , &#39;k, &#39;r) rf</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">    val cd   : (&#39;n cd  , &#39;n, z i  , &#39;s ii , &#39;k, &#39;r) rf</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">    val d    : (&#39;n d   , &#39;n, z i  , &#39;s ii , &#39;k, &#39;r) rf</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">    val dc   : (&#39;n dc  , &#39;n, z i  , &#39;s ii , &#39;k, &#39;r) rf</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">    val dcc  : (&#39;n dcc , &#39;n, z i  , &#39;s ii , &#39;k, &#39;r) rf</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">    val dccc : (&#39;n dccc, &#39;n, z i  , &#39;s ii , &#39;k, &#39;r) rf</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">    val cm   : (&#39;n cm  , &#39;n, z i  , &#39;s ii , &#39;k, &#39;r) rf</span><br style="font-family:courier new,monospace">

<br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">    val m    : (&#39;n m   , &#39;n, z    , &#39;s i  , &#39;k, &#39;r) rf</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">    val mm   : (&#39;n mm  , &#39;n, z    , &#39;s i  , &#39;k, &#39;r) rf</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">    val mmm  : (&#39;n mmm , &#39;n, z    , &#39;s i  , &#39;k, &#39;r) rf</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">end</span><br style="font-family:courier new,monospace"><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">structure Roman :&gt; ROMAN = struct</span><br style="font-family:courier new,monospace">

<br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">    datatype    z = Z</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">    datatype &#39;n i = I of &#39;n</span><br style="font-family:courier new,monospace">

<br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">    type &#39;n ii   = &#39;n i i</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">    type &#39;n iii  = &#39;n i ii</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">    type &#39;n iv   = &#39;n i iii</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">    type &#39;n v    = &#39;n i iv</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">    type &#39;n vi   = &#39;n i v</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">    type &#39;n vii  = &#39;n i vi</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">    type &#39;n viii = &#39;n i vii</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">    type &#39;n ix   = &#39;n i viii</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">    type &#39;n x    = &#39;n i ix</span><br style="font-family:courier new,monospace"><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">    type &#39;n xx   = &#39;n x x</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">    type &#39;n xxx  = &#39;n x xx</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">    type &#39;n xl   = &#39;n x xxx</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">    type &#39;n l    = &#39;n x xl</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">    type &#39;n lx   = &#39;n x l</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">    type &#39;n lxx  = &#39;n x lx</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">    type &#39;n lxxx = &#39;n x lxx</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">    type &#39;n xc   = &#39;n x lxxx</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">    type &#39;n c    = &#39;n x xc</span><br style="font-family:courier new,monospace">

<br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">    type &#39;n cc   = &#39;n c c</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">    type &#39;n ccc  = &#39;n c cc</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">    type &#39;n cd   = &#39;n c ccc</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">    type &#39;n d    = &#39;n c cd</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">    type &#39;n dc   = &#39;n c d</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">    type &#39;n dcc  = &#39;n c dc</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">    type &#39;n dccc = &#39;n c dcc</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">    type &#39;n cm   = &#39;n c dccc</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">    type &#39;n m    = &#39;n c cm</span><br style="font-family:courier new,monospace"><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">    type &#39;n mm   = &#39;n m m</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">    type &#39;n mmm  = &#39;n m mm</span><br style="font-family:courier new,monospace"><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">    type &#39;n r = int</span><br style="font-family:courier new,monospace">

<br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">    datatype (&#39;n, &#39;s) r&#39; = R of int</span><br style="font-family:courier new,monospace"><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">    type (&#39;n, &#39;m, &#39;s, &#39;t, &#39;k, &#39;r) rf =</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">        ((&#39;n, &#39;s) r&#39; -&gt; &#39;k) -&gt; (((&#39;m, &#39;t) r&#39; -&gt; &#39;k) -&gt; &#39;r) -&gt; &#39;r</span><br style="font-family:courier new,monospace">

<br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">    fun toInt n = n</span><br style="font-family:courier new,monospace"><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">    local</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">        fun unR (R n) = n</span><br style="font-family:courier new,monospace"><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">        fun ret  a f = f a</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">        fun lift   f = ret o f</span><br style="font-family:courier new,monospace"><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">        fun mkR n k = lift (fn g =&gt; g o R o (fn x =&gt; x + n) o unR) k</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">    in</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">        fun &lt;|  f = ret unR f</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">        fun  |&gt; f = f (R 0)</span><br style="font-family:courier new,monospace"><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">        fun i    k = mkR    1 k</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">        fun ii   k = mkR    2 k</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">        fun iii  k = mkR    3 k</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">        fun iv   k = mkR    4 k</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">        fun v    k = mkR    5 k</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">        fun vi   k = mkR    6 k</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">        fun vii  k = mkR    7 k</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">        fun viii k = mkR    8 k</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">        fun ix   k = mkR    9 k</span><br style="font-family:courier new,monospace">

<br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">        fun x    k = mkR   10 k</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">        fun xx   k = mkR   20 k</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">        fun xxx  k = mkR   30 k</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">        fun xl   k = mkR   40 k</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">        fun l    k = mkR   50 k</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">        fun lx   k = mkR   60 k</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">        fun lxx  k = mkR   70 k</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">        fun lxxx k = mkR   80 k</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">        fun xc   k = mkR   90 k</span><br style="font-family:courier new,monospace"><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">        fun c    k = mkR  100 k</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">        fun cc   k = mkR  200 k</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">        fun ccc  k = mkR  300 k</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">        fun cd   k = mkR  400 k</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">        fun d    k = mkR  500 k</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">        fun dc   k = mkR  600 k</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">        fun dcc  k = mkR  700 k</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">        fun dccc k = mkR  800 k</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">        fun cm   k = mkR  900 k</span><br style="font-family:courier new,monospace">

<br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">        fun m    k = mkR 1000 k</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">        fun mm   k = mkR 2000 k</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">        fun mmm  k = mkR 3000 k</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">    end</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">end</span><br style="font-family:courier new,monospace">
</div><br>