(.using
  [library
   [lux "*"
    [abstract
     [equivalence {"+" Equivalence}]
     [hash {"+" Hash}]]
    [control
     [pipe {"+" case>}]]
    [data
     [text
      ["%" format {"+" Format}]]]
    [math
     [number
      ["n" nat]
      ["i" int]]]]])

(type: .public Register
  Nat)

(type: .public Variable
  (Variant
   {#Local Register}
   {#Foreign Register}))

(implementation: .public equivalence
  (Equivalence Variable)
  
  (def: (= reference sample)
    (case [reference sample]
      (^template [<tag>]
        [[{<tag> reference'} {<tag> sample'}]
         (n.= reference' sample')])
      ([#Local] [#Foreign])

      _
      #0)))

(implementation: .public hash
  (Hash Variable)
  
  (def: &equivalence
    ..equivalence)
  
  (def: hash
    (|>> (case> (^template [<factor> <tag>]
                  [{<tag> register}
                   (|> register
                       (# n.hash hash)
                       (n.* <factor>))])
                ([2 #Local]
                 [3 #Foreign])))))

(template: .public (self)
  [{..#Local 0}])

(def: .public self?
  (-> Variable Bit)
  (|>> (case> (^ (..self))
              true

              _
              false)))

(def: .public format
  (Format Variable)
  (|>> (case> {#Local local}
              (%.format "+" (%.nat local))
              
              {#Foreign foreign}
              (%.format "-" (%.nat foreign)))))
