; Bench fixture: HOF + polymorphic ADT pipeline.
;
; Builds a polymorphic List<Int> of length n, then folds it with a
; higher-order function `inc` to compute the sum of incremented
; elements. Distinct from bench_list_sum:
;   1. Uses `(data List (vars a) ...)` — polymorphic ADT, exercises
;      the 13b/14a polymorphism-at-runtime path. The Cons cell
;      layout is the same width as bench_list_sum's IntList ICons,
;      but the type-arg substitution is the additional code path.
;   2. The traversal is via `fold_with_fn` — an HOF taking
;      `(fn-type (params (own a)) (ret (own (con Int))))` as its first param.
;      Each step calls `(app f h)` — an indirect call through the
;      fn-arg. This is the only fixture that exercises tight-loop
;      indirect dispatch.
;
; Build phase is alloc-heavy (n Cons cells); fold phase is
; dispatch-heavy (n indirect calls). Per-iteration cost should be
; visibly higher than bench_list_sum's direct sum.
;
; Result for size n (using inc(x) = x+1):
;   sum (inc 0) + (inc 1) + ... + (inc (n-1)) = sum 1..n = n*(n+1)/2
;
; Sizes:
;   100_000   ->     5_000_050_000
; 1_000_000   ->   500_000_500_000
; 3_000_000   -> 4_500_001_500_000

(module bench_hof_pipeline

  (data List (vars a)
    (doc "Polymorphic singly-linked list. Same shape as list_map_poly's List, replicated here so the bench fixture is self-contained.")
    (ctor Nil)
    (ctor Cons a (con List a)))

  (fn build_n
    (doc "Build [0, 1, ..., n-1] :: List Int. Tail-recursive accumulator form.")
    (type
      (fn-type
        (params (own (con Int)) (own (con List (con Int))))
        (ret (own (con List (con Int))))))
    (params n acc)
    (body
      (if (app eq n 0)
        acc
        (tail-app build_n
          (app - n 1)
          (term-ctor List Cons (app - n 1) acc)))))

  (fn inc
    (doc "Add 1 to an Int. Used as the HOF argument to fold_with_fn.")
    (type (fn-type (params (own (con Int))) (ret (own (con Int)))))
    (params x)
    (body (app + x 1)))

  (fn fold_with_fn
    (doc "Polymorphic foldl-with-mapping. Apply f:(a)->Int to every element of xs, sum into acc. Tail-recursive on (xs, acc); the f arg is forwarded unchanged.")
    (type
      (forall (vars a)
        (fn-type
          (params (borrow (fn-type (params (own a)) (ret (own (con Int)))))
                  (own (con List a))
                  (own (con Int)))
          (ret (own (con Int))))))
    (params f xs acc)
    (body
      (match xs
        (case (pat-ctor Nil) acc)
        (case (pat-ctor Cons h t)
          (tail-app fold_with_fn f t (app + acc (app f h)))))))

  (fn run_one
    (doc "Build [0..n-1], fold with inc, print sum of (inc x).")
    (type (fn-type (params (own (con Int))) (ret (own (con Unit))) (effects IO)))
    (params n)
    (body
      (app print
        (app fold_with_fn inc
          (app build_n n (term-ctor List Nil))
          0))))

  (fn main
    (type (fn-type (params) (ret (own (con Unit))) (effects IO)))
    (params)
    (body
      (seq (app run_one 100000)
      (seq (app run_one 1000000)
           (app run_one 3000000))))))
