aboutsummaryrefslogtreecommitdiff
path: root/stdlib/source/library/lux/data/sum.lux
blob: 2cd4b6794d09541cddb6914d54725ee1ae9c61d1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
(.require
 [library
  [lux (.except left right)
   [abstract
    [equivalence (.only Equivalence)]
    [hash (.only Hash)]]
   [data
    [collection
     ["[0]" list (.use "[1]#[0]" mix)]]]]])

(with_template [<right?> <name>]
  [(def .public (<name> value)
     (All (_ left right)
       (-> <name> (Or left right)))
     {0 <right?> value})]

  [#0 left]
  [#1 right])

(def .public (either on_left on_right)
  (All (_ a b c)
    (-> (-> a c) (-> b c)
        (-> (Or a b) c)))
  (function (_ input)
    (when input
      {0 #0 l} (on_left l)
      {0 #1 r} (on_right r))))

(def .public (then on_left on_right)
  (All (_ l l' r r')
    (-> (-> l l') (-> r r')
        (-> (Or l r) (Or l' r'))))
  (function (_ input)
    (when input
      {0 #0 l} {0 #0 (on_left l)}
      {0 #1 r} {0 #1 (on_right r)})))

(with_template [<right?> <side> <name>]
  [(def .public (<name> it)
     (All (_ t0 t1) (-> (List (Or t0 t1)) (List <side>)))
     ... TODO: Use the more obvious implementation once "tail recursion modulo cons" is added to the compiler.
     (list#mix (function (_ head tail)
                 (when head
                   {0 <right?> head}
                   (list.partial head tail)

                   _
                   tail))
               (list)
               (list.reversed it)))]

  [#0 t0 lefts]
  [#1 t1 rights]
  )

(def .public (partition xs)
  (All (_ a b) (-> (List (Or a b)) [(List a) (List b)]))
  (when xs
    {.#End}
    [{.#End} {.#End}]

    {.#Item x xs'}
    (let [[lefts rights] (partition xs')]
      (when x
        {0 #0 x'}  [{.#Item x' lefts} rights]
        {0 #1 x'} [lefts {.#Item x' rights}]))))

(def .public (equivalence left right)
  (All (_ l r) (-> (Equivalence l) (Equivalence r) (Equivalence (Or l r))))
  (implementation
   (def (= reference sample)
     (when [reference sample]
       [{.#Left reference} {.#Left sample}]
       (of left = reference sample)

       [{.#Right reference} {.#Right sample}]
       (of right = reference sample)

       _
       false))))

(def .public (hash left right)
  (All (_ l r) (-> (Hash l) (Hash r) (Hash (Or l r))))
  (implementation
   (def equivalence
     (..equivalence (of left equivalence)
                    (of right equivalence)))
   (def (hash value)
     (.nat (when value
             {.#Left value}
             (.int_*# +2 (.int (of left hash value)))

             {.#Right value}
             (.int_*# +3 (.int (of right hash value))))))))