aboutsummaryrefslogtreecommitdiff
path: root/stdlib/source/lux/macro/poly/functor.lux
blob: 139cc5f7ec12828b1f0715f9664b9ad600481ddd (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
95
(;module:
  lux
  (lux (control [monad #+ do Monad]
                [functor]
                ["p" parser])
       (data [text]
             text/format
             (coll [list "L/" Monad<List> Monoid<List>])
             [product])
       [macro #+ Monad<Lux> with-gensyms]
       (macro [code]
              [syntax #+ syntax: Syntax]
              (syntax [common])
              [poly #+ poly:])
       [type]
       ))

(poly: #export Functor<?>
  (do @
    [#let [type-funcC (code;local-symbol "\u0000type-funcC")
           funcC (code;local-symbol "\u0000funcC")
           inputC (code;local-symbol "\u0000inputC")]
     *env* poly;env
     inputT poly;peek
     [polyC varsC non-functorT] (poly;local (list inputT)
                                            (poly;polymorphic poly;any))
     #let [num-vars (list;size varsC)]
     #let [@Functor (: (-> Type Code)
                       (function [unwrappedT]
                         (if (n.= +1 num-vars)
                           (` (functor;Functor (~ (poly;to-ast *env* unwrappedT))))
                           (let [paramsC (|> num-vars n.dec list;indices (L/map (|>. %n code;local-symbol)))]
                             (` (All [(~@ paramsC)]
                                  (functor;Functor ((~ (poly;to-ast *env* unwrappedT)) (~@ paramsC)))))))))
           Arg<?> (: (-> Code (poly;Poly Code))
                     (function Arg<?> [valueC]
                       ($_ p;either
                           ## Type-var
                           (do p;Monad<Parser>
                             [#let [varI (|> num-vars (n.* +2) n.dec)]
                              _ (poly;var varI)]
                             (wrap (` ((~ funcC) (~ valueC)))))
                           ## Variants
                           (do @
                             [_ (wrap [])
                              membersC (poly;variant (p;many (Arg<?> valueC)))]
                             (wrap (` (case (~ valueC)
                                        (~@ (L/join (L/map (function [[tag memberC]]
                                                             (list (` ((~ (code;nat tag)) (~ valueC)))
                                                                   (` ((~ (code;nat tag)) (~ memberC)))))
                                                           (list;enumerate membersC))))))))
                           ## Tuples
                           (do p;Monad<Parser>
                             [pairsCC (: (poly;Poly (List [Code Code]))
                                         (poly;tuple (loop [idx +0
                                                            pairsCC (: (List [Code Code])
                                                                       (list))]
                                                       (p;either (let [slotC (|> idx %n (format "\u0000slot") code;local-symbol)]
                                                                   (do @
                                                                     [_ (wrap [])
                                                                      memberC (Arg<?> slotC)]
                                                                     (recur (n.inc idx)
                                                                            (L/compose pairsCC (list [slotC memberC])))))
                                                                 (wrap pairsCC)))))]
                             (wrap (` (case (~ valueC)
                                        [(~@ (L/map product;left pairsCC))]
                                        [(~@ (L/map product;right pairsCC))]))))
                           ## Functions
                           (do @
                             [_ (wrap [])
                              #let [outL (code;local-symbol "\u0000outL")]
                              [inT+ outC] (poly;function (p;many poly;any)
                                            (Arg<?> outL))
                              #let [inC+ (|> (list;size inT+) n.dec
                                             (list;n.range +0)
                                             (L/map (|>. %n (format "\u0000inC") code;local-symbol)))]]
                             (wrap (` (function [(~@ inC+)]
                                        (let [(~ outL) ((~ valueC) (~@ inC+))]
                                          (~ outC))))))
                           ## Recursion
                           (do p;Monad<Parser>
                             [_ poly;recursive-call]
                             (wrap (` ((~' map) (~ funcC) (~ valueC)))))
                           ## Bound type-variables
                           (do p;Monad<Parser>
                             [_ poly;any]
                             (wrap valueC))
                           )))]
     [_ _ outputC] (: (poly;Poly [Code (List Code) Code])
                      (p;either (poly;polymorphic
                                 (Arg<?> inputC))
                                (p;fail (format "Cannot create Functor for: " (%type inputT)))))]
    (wrap (` (: (~ (@Functor inputT))
                (struct (def: ((~' map) (~ funcC) (~ inputC))
                          (~ outputC))))))))