aboutsummaryrefslogtreecommitdiff
path: root/stdlib/source/lux/type/refinement.lux
blob: 55aa3cdd7ef6cd3ca9b7ca3ded9c8ffa6e5488f2 (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
(.module:
  [lux #- Ref type]
  (lux (control [predicate #+ Pred]
                [monad #+ do]
                ["p" parser])
       (data ["e" error #+ Error])
       (lang [type "type/" Eq<Type>])
       (type abstract)
       [macro]
       (macro ["s" syntax #+ syntax:]
              [poly])))

(abstract: #export (Ref t r)
  {#.doc "A refinement 'r' on type 't' based on a predicate."}
  
  {#value t
   #predicate (Pred t)}

  (def: #export (refinement predicate)
    (All [t]
      (Ex [r]
        (-> (Pred t) (-> t (Maybe (Ref t r))))))
    (function [un-refined]
      (if (predicate un-refined)
        (#.Some (@abstraction {#value un-refined
                               #predicate predicate}))
        #.None)))

  (do-template [<name> <output> <slot>]
    [(def: #export (<name> refined)
       (All [t r] (-> (Ref t r) <output>))
       (|> refined @representation (get@ <slot>)))]

    [un-refine t        #value]
    [predicate (Pred t) #predicate]
    )

  (def: #export (lift transform)
    (All [t r]
      (-> (-> t t)
          (-> (Ref t r) (Maybe (Ref t r)))))
    (function [refined]
      (let [[value predicate] (@representation refined)
            value' (transform value)]
        (if (predicate value')
          (#.Some (@abstraction {#value value'
                                 #predicate predicate}))
          #.None))))
  )

(def: (refinement-type constructor-type)
  (-> Type (Error Type))
  (<| (poly.run constructor-type)
      (do p.Monad<Parser>
        [[un-refinedT outputT] (poly.function poly.any poly.any)
         refined-ex (<| (poly.local (list outputT))
                        poly.apply (p.after (poly.this .Maybe))
                        poly.apply (p.after (poly.this ..Ref))
                        (p.after (poly.this un-refinedT))
                        poly.existential)]
        (wrap (.type (..Ref un-refinedT (#.Ex refined-ex)))))))

(syntax: #export (type [refinement s.symbol])
  (do @
    [constructorT (macro.find-type refinement)
     refinementT (case (refinement-type constructorT)
                   (#e.Success refinementT)
                   (wrap refinementT)

                   (#e.Error error)
                   (p.fail error))]
    (wrap (list (type.to-code refinementT)))))