; Iter 15b — second consumer demo.
; Imports both std_maybe and std_list. Exercises every combinator at
; least once. xs is a top-level fn `() -> List<Int>` (consts cannot
; reference user fns; the brief flagged this).

(module std_list_demo

  (import std_maybe)
  (import std_list)

  (fn inc
    (doc "Add 1 to an Int. Used as the (a -> b) arg to map.")
    (type (fn-type (params (con Int)) (ret (con Int))))
    (params x)
    (body (app + x 1)))

  (fn add
    (doc "Binary +. Used as the fold accumulator op.")
    (type (fn-type (params (con Int) (con Int)) (ret (con Int))))
    (params a b)
    (body (app + a b)))

  (fn is_even
    (doc "Predicate: x mod 2 == 0.")
    (type (fn-type (params (con Int)) (ret (con Bool))))
    (params x)
    (body (app == (app % x 2) 0)))

  (fn double
    (doc "Multiply by 2. Used as the map arg.")
    (type (fn-type (params (con Int)) (ret (con Int))))
    (params x)
    (body (app * x 2)))

  (const xs
    (doc "The canonical list [1,2,3,4,5] for the demo. Pure ctor expression, so a const works.")
    (type (con std_list.List (con Int)))
    (body
      (term-ctor std_list.List Cons 1
        (term-ctor std_list.List Cons 2
          (term-ctor std_list.List Cons 3
            (term-ctor std_list.List Cons 4
              (term-ctor std_list.List Cons 5
                (term-ctor std_list.List Nil))))))))

  (fn main
    (doc "Drive each std_list combinator once. Expected outputs (per line): 5, false, true, 1, 4, 10, 5, 2, 2, 15, 15.")
    (type (fn-type (params) (ret (con Unit)) (effects IO)))
    (params)
    (body
      (seq (do io/print_int  (app std_list.length xs))
      (seq (do io/print_bool (app std_list.is_empty xs))
      (seq (do io/print_bool (app std_list.is_empty (term-ctor std_list.List Nil)))
      (seq (do io/print_int  (app std_maybe.from_maybe -1 (app std_list.head xs)))
      (seq (do io/print_int  (app std_list.length (app std_maybe.from_maybe xs (app std_list.tail xs))))
      (seq (do io/print_int  (app std_list.length (app std_list.append xs xs)))
      (seq (do io/print_int  (app std_maybe.from_maybe -1 (app std_list.head (app std_list.reverse xs))))
      (seq (do io/print_int  (app std_maybe.from_maybe -1 (app std_list.head (app std_list.map double xs))))
      (seq (do io/print_int  (app std_list.length (app std_list.filter is_even xs)))
      (seq (do io/print_int  (app std_list.fold_left add 0 xs))
           (do io/print_int  (app std_list.fold_right add 0 xs)))))))))))))))
