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
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
use super::{LConcatComposeFunctor, LCons, LNil, LPrependToFunctor, TList};
use crate::{
    functional::{ApplicativeFunctor, ApplyFunctor, FMapFunctor, Functor},
    maybe::{Maybe, MaybeMap, MaybeMapFunctor, UnwrapOr, UnwrapOrFunctor},
    tuple::{FirstOf, FirstOfFunctor, Pair, SecondOf, SecondOfFunctor},
};
use std::marker::PhantomData;

/// A type operator that apply a [Functor] to all types in [TList].
pub trait LMapOp<Func>
where
    Self: TList,
    Self::Output: TList,
{
    type Output;
}

pub type LMapOpOutput<List, Func> = <List as LMapOp<Func>>::Output;

impl<Func> LMapOp<Func> for LNil {
    type Output = LNil;
}

impl<Func, Head, Tail> LMapOp<Func> for LCons<Head, Tail>
where
    Func: Functor<Head>,
    Tail: TList + LMapOp<Func>,
{
    type Output = LCons<ApplyFunctor<Func, Head>, LMapOpOutput<Tail, Func>>;
}

/// A [Functor] that maps values in [TList] with `Func`.
pub struct LMapFunctor<Func> {
    _phantom: PhantomData<Func>,
}

pub type LMap<List, Func> = ApplyFunctor<LMapFunctor<Func>, List>;

impl<List, Func> Functor<List> for LMapFunctor<Func>
where
    List: TList + LMapOp<Func>,
{
    type Output = LMapOpOutput<List, Func>;
}

/// A type operator that accumulates all values in [TList].
pub trait LFoldOp<Init, Func>
where
    Self: TList,
{
    type Output;
}

pub type LFoldOpOutput<List, Init, Func> = <List as LFoldOp<Init, Func>>::Output;

impl<Init, Func> LFoldOp<Init, Func> for LNil {
    type Output = Init;
}

impl<Init, Func, Head, Tail> LFoldOp<Init, Func> for LCons<Head, Tail>
where
    Func: Functor<(Init, Head)>,
    Tail: TList + LFoldOp<ApplyFunctor<Func, (Init, Head)>, Func>,
{
    type Output = LFoldOpOutput<Tail, ApplyFunctor<Func, (Init, Head)>, Func>;
}

/// A [Functor] that maps values in [TList] with `Func`.
pub struct LFoldFunctor<Init, Func> {
    _phantom: PhantomData<(Init, Func)>,
}

pub type LFold<List, Init, Func> = ApplyFunctor<LFoldFunctor<Init, Func>, List>;

impl<List, Init, Func> Functor<List> for LFoldFunctor<Init, Func>
where
    List: TList + LFoldOp<Init, Func>,
{
    type Output = LFoldOpOutput<List, Init, Func>;
}

/// Filters the values in [TList].
pub trait LFilterOp<Func>
where
    Self: TList,
    Self::Output: TList,
{
    type Output;
}

pub type LFilterOpOutput<List, Func> = <List as LFilterOp<Func>>::Output;

impl<Func> LFilterOp<Func> for LNil {
    type Output = LNil;
}

impl<Func, Head, Tail> LFilterOp<Func> for LCons<Head, Tail>
where
    Func: Functor<Head>,
    Tail: TList + LFilterOp<Func>,
    Func::Output: Maybe,
    MaybeMapFunctor<LPrependToFunctor<LFilterOpOutput<Tail, Func>>>:
        Functor<ApplyFunctor<Func, Head>>,
    UnwrapOrFunctor<LFilterOpOutput<Tail, Func>>:
        Functor<MaybeMap<ApplyFunctor<Func, Head>, LPrependToFunctor<LFilterOpOutput<Tail, Func>>>>,
    UnwrapOr<
        MaybeMap<ApplyFunctor<Func, Head>, LPrependToFunctor<LFilterOpOutput<Tail, Func>>>,
        LFilterOpOutput<Tail, Func>,
    >: TList,
{
    type Output = UnwrapOr<
        MaybeMap<ApplyFunctor<Func, Head>, LPrependToFunctor<LFilterOpOutput<Tail, Func>>>,
        LFilterOpOutput<Tail, Func>,
    >;
}

/// A [Functor] that filters values in [TList] with `Func`.
pub struct LFilterFunctor<Func> {
    _phantom: PhantomData<Func>,
}

pub type LFilter<List, Func> = ApplyFunctor<LFilterFunctor<Func>, List>;

impl<List, Func> Functor<List> for LFilterFunctor<Func>
where
    List: TList + LFilterOp<Func>,
{
    type Output = LFilterOpOutput<List, Func>;
}

/// A [LMap]-like operator that maintains internal state.
pub trait LScanOp<State, Func>
where
    Self: TList,
    Self::Output: TList,
{
    type Output;
    type State;
}

pub type LScanOpOutput<List, State, Func> = <List as LScanOp<State, Func>>::Output;
pub type LScanOpState<List, State, Func> = <List as LScanOp<State, Func>>::State;

impl<State, Func> LScanOp<State, Func> for LNil {
    type Output = LNil;
    type State = State;
}

impl<State, Func, Head, Tail> LScanOp<State, Func> for LCons<Head, Tail>
where
    Func: Functor<(State, Head)>,
    Tail: TList + LScanOp<SecondOf<ApplyFunctor<Func, (State, Head)>>, Func>,
    FirstOfFunctor: Functor<ApplyFunctor<Func, (State, Head)>>,
    SecondOfFunctor: Functor<ApplyFunctor<Func, (State, Head)>>,
    ApplyFunctor<Func, (State, Head)>: Pair,
{
    type Output =
        LCons<FirstOf<ApplyFunctor<Func, (State, Head)>>, LScanOpOutput<Tail, Self::State, Func>>;
    type State = SecondOf<ApplyFunctor<Func, (State, Head)>>;
}

/// A [Functor] that maps values in [TList] with `Func` with internal state.
pub struct LScanFunctor<Init, Func> {
    _phantom: PhantomData<(Init, Func)>,
}

pub type LScan<List, Init, Func> = ApplyFunctor<LScanFunctor<Init, Func>, List>;

impl<List, Init, Func> Functor<List> for LScanFunctor<Init, Func>
where
    List: TList + LScanOp<Init, Func>,
{
    type Output = LScanOpOutput<List, Init, Func>;
}

// impl FMap for TList

impl<Func> Functor<LNil> for FMapFunctor<Func> {
    type Output = LNil;
}

impl<Func, Head, Tail> Functor<LCons<Head, Tail>> for FMapFunctor<Func>
where
    Tail: TList,
    LCons<Head, Tail>: LMapOp<Func>,
{
    type Output = LMapOpOutput<LCons<Head, Tail>, Func>;
}

// impl Applicative for TList

impl Functor<LNil> for ApplicativeFunctor<LNil> {
    type Output = LNil;
}

impl<LHead, LTail> Functor<LCons<LHead, LTail>> for ApplicativeFunctor<LNil>
where
    LTail: TList,
{
    type Output = LNil;
}

impl<RHead, RTail> Functor<LNil> for ApplicativeFunctor<LCons<RHead, RTail>>
where
    RTail: TList,
{
    type Output = LNil;
}

impl<LHead, LTail, RHead, RTail> Functor<LCons<LHead, LTail>>
    for ApplicativeFunctor<LCons<RHead, RTail>>
where
    LTail: TList,
    RTail: TList,
    LCons<LHead, LTail>: LMapOp<ApplyToTListFunctor<LCons<RHead, RTail>>>,
    LMapOpOutput<LCons<LHead, LTail>, ApplyToTListFunctor<LCons<RHead, RTail>>>:
        LFoldOp<LNil, LConcatComposeFunctor>,
{
    type Output = LFoldOpOutput<
        LMapOpOutput<LCons<LHead, LTail>, ApplyToTListFunctor<LCons<RHead, RTail>>>,
        LNil,
        LConcatComposeFunctor,
    >;
}

// auxiliary functor for Applicative interface

/// A [Functor] that applies input functor to `List`.
pub struct ApplyToTListFunctor<List>
where
    List: TList,
{
    _phantom: PhantomData<List>,
}

pub type ApplyToTList<Func, List> = ApplyFunctor<ApplyToTListFunctor<List>, Func>;

impl<Func, List> Functor<Func> for ApplyToTListFunctor<List>
where
    List: TList + LMapOp<Func>,
    LMapOpOutput<List, Func>: TList,
{
    type Output = LMapOpOutput<List, Func>;
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::{
        boolean::Boolean,
        control::{IfElsePredicate, IfElsePredicateOutput, IfSameOutput},
        functional::{Applicative, FMap},
        maybe::{Just, Nothing},
        numeric::{AddOneFunctor, SubOneFunctor},
        TListType,
    };
    use std::ops::Add;
    use typenum::{consts::*, Add1, Exp, IsLess, Le, Pow, Sum, Unsigned, B1};

    // Plus one to typenum unsigned numbers
    struct PlusOne;

    impl<Input> Functor<Input> for PlusOne
    where
        Input: Unsigned + Add<B1>,
    {
        type Output = Add1<Input>;
    }

    type List1 = TListType![U1, U2, U3];
    type List2 = LMap<List1, PlusOne>;
    type Assert1 = IfSameOutput<(), List2, TListType![U2, U3, U4]>;

    // Box every type
    struct BoxFunc;

    impl<Input> Functor<Input> for BoxFunc {
        type Output = Box<Input>;
    }

    type List3 = TListType![String, [i64; 7], isize, (), (f64, f32)];
    type List4 = LMap<List3, BoxFunc>;
    type Assert2 = IfSameOutput<
        (),
        List4,
        TListType! {
            Box<String>,
            Box<[i64; 7]>,
            Box<isize>,
            Box<()>,
            Box<(f64, f32)>
        },
    >;

    // Sum of list
    struct SumFunc;

    impl<Init, Input> Functor<(Init, Input)> for SumFunc
    where
        Init: Unsigned + Add<Input>,
        Input: Unsigned,
    {
        type Output = Sum<Init, Input>;
    }

    type List5 = TListType![U3, U5, U7];
    type SumOutcome = LFold<List5, U0, SumFunc>;
    type Assert3 = IfSameOutput<(), SumOutcome, U15>;

    // Count # of elements in list
    struct CountFunc;

    impl<Init, Input> Functor<(Init, Input)> for CountFunc
    where
        Init: Unsigned + Add<B1>,
    {
        type Output = Add1<Init>;
    }

    type List6 = TListType![u8, u16, u32, u64, i8, i16, i32, i64, f32, f64];
    type CountOutcome = LFold<List6, U0, CountFunc>;
    type Assert4 = IfSameOutput<(), CountOutcome, U10>;

    // Filter by threshold
    struct ThresholdFunc;

    impl<Input> Functor<Input> for ThresholdFunc
    where
        Input: Unsigned + IsLess<U5>,
        Le<Input, U5>: Boolean,
        Just<Input>: IfElsePredicate<Le<Input, U5>, Nothing>,
    {
        type Output = IfElsePredicateOutput<Just<Input>, Le<Input, U5>, Nothing>;
    }

    type List7 = TListType![U8, U4, U0, U6, U9];
    type ThresholdOutcome = LFilter<List7, ThresholdFunc>;
    type Assert5 = IfSameOutput<(), ThresholdOutcome, TListType![U4, U0]>;

    // Power of values
    struct PowerScanFunc;

    impl<State, Input> Functor<(State, Input)> for PowerScanFunc
    where
        Input: Unsigned + Pow<State>,
        State: Unsigned + Add<B1>,
    {
        type Output = (Exp<Input, State>, Add1<State>);
    }

    type List8 = TListType![U3, U2, U7, U0, U5];
    type PowerOutput = LScan<List8, U0, PowerScanFunc>;
    type Assert6 = IfSameOutput<(), PowerOutput, TListType![U1, U2, U49, U0, U625]>;

    // FMap interface
    type Assert7 =
        IfSameOutput<(), FMap<TListType![U1, U2, U3], AddOneFunctor>, TListType![U2, U3, U4]>;

    // Applicative interface
    type List9 = TListType![AddOneFunctor, SubOneFunctor];
    type List10 = TListType![U1, U2, U3];

    type Assert8 = IfSameOutput<(), Applicative<LNil, LNil>, LNil>;
    type Assert9 = IfSameOutput<(), Applicative<List9, LNil>, LNil>;
    type Assert10 = IfSameOutput<(), Applicative<LNil, List10>, LNil>;
    type Assert11 =
        IfSameOutput<(), Applicative<List9, List10>, TListType![U2, U3, U4, U0, U1, U2]>;

    #[test]
    fn list_functional_test() {
        let _: Assert1 = ();
        let _: Assert2 = ();
        let _: Assert3 = ();
        let _: Assert4 = ();
        let _: Assert5 = ();
        let _: Assert6 = ();
        let _: Assert7 = ();
        let _: Assert8 = ();
        let _: Assert9 = ();
        let _: Assert10 = ();
        let _: Assert11 = ();
    }
}