;; Data Analysis with R Interop
;; Demonstrates seamless integration between Arl and R
;;
;; NOTE ON R INTEROP: All R functions are directly callable from Arl:
;;
;;   (mean (c 1 2 3))              ; call R's mean() and c()
;;   (seq :from 1 :to 10 :by 2)   ; named arguments via keywords
;;
;; Arl also provides r-call, which bypasses bindings in intermediate
;; scopes to reach objects in R environments that Arl's stack isn't
;; managing. For example:
;;
;;   (r-call "mean" (list (c 1 2 3)))         ; look up "mean" by string name
;;   (r-call "fn" args (some-environment))    ; search a specific environment
;;
;; In practice, direct calls are simpler and preferred. This example
;; uses direct calls throughout.

(import assert :refer :all)
(import binding :refer :all)
(import control :refer :all)
(import dict :refer :all)
(import display :refer :all)
(import looping :refer :all)
(import threading :refer :all)

;; Deterministic randomness for reproducible examples
(set.seed 123)

;; ============================================================================
;; Working with R Vectors and Lists
;; ============================================================================

(println "=== R Interop Basics ===\n")

;; Create R vectors directly
(define nums (c 1 2 3 4 5 6 7 8 9 10))
(assert-equal (list 1 2 3 4 5 6 7 8 9 10) (as.list nums))
(println (string-concat "R vector: " nums))

;; Use R statistical functions
(define mean-val (mean nums))
(define median-val ((:: stats median) nums))
(define sd-val ((:: stats sd) nums))
(assert-equal 5.5 mean-val)
(assert-equal 5.5 median-val)
(assert-true (> sd-val 3.0))
(assert-true (< sd-val 3.1))

(println (string-concat "Mean: " mean-val))
(println (string-concat "Median: " median-val))
(println (string-concat "SD: " sd-val))

;; ============================================================================
;; Generating Data with R
;; ============================================================================

(println "\n=== Generating Data ===\n")

;; Generate random normal data
(define random-data ((:: stats rnorm) 100))
(println (string-concat "Generated 100 random numbers"))
(println (string-concat "First 10: " ((:: utils head) random-data 10)))

;; Summary statistics
(println "\nSummary:")
(println (summary random-data))

;; ============================================================================
;; Data Transformation Pipeline
;; ============================================================================

(println "\n=== Data Transformation Pipeline ===\n")

;; Create sample data
(define scores (c 85 92 78 90 88 76 95 89 91 87))
(println (string-concat "Original scores: " scores))

;; Transform data using Arl's higher-order functions
(define score-list (as.list scores))

;; Add 5 points to each score
(define adjusted-scores (map (lambda (x) (+ x 5)) score-list))
(assert-equal (list 90 97 83 95 93 81 100 94 96 92) adjusted-scores)
(println (string-concat "After adding 5 points: " adjusted-scores))

;; Filter passing scores (>= 80)
(define passing (filter (lambda (x) (>= x 80)) adjusted-scores))
(assert-equal 10 (length passing))
(println (string-concat "Passing scores: " passing))

;; Calculate average of passing scores
(define passing-avg (/ (reduce + passing) (length passing)))
(assert-equal 92.1 passing-avg)
(println (string-concat "Average of passing scores: " passing-avg))

;; ============================================================================
;; Working with Named Lists (Data Frames)
;; ============================================================================

(println "\n=== Working with Named Lists ===\n")

;; Create a named list (similar to R's named vector)
(define student-data
  (dict
   :names (list "Alice" "Bob" "Carol" "Dave" "Eve")
   :scores (list 85 92 78 90 88)
   :ages (list 20 21 19 22 20)))

(println "Student data:")
(println student-data)

;; Extract and process names
(define names (get "names" student-data))
(assert-equal (list "Alice" "Bob" "Carol" "Dave" "Eve") names)
(println (string-concat "\nStudent names: " names))

;; Extract and analyze scores
(define scores-data (get "scores" student-data))
(assert-equal (list 85 92 78 90 88) scores-data)
(println (string-concat "Scores: " scores-data))

;; ============================================================================
;; Statistical Analysis
;; ============================================================================

(println "\n=== Statistical Analysis ===\n")

;; Create two groups
(define group-a (c 23 25 21 24 22 26 20))
(define group-b (c 30 32 28 31 29 33 27))

(assert-equal 23 (mean group-a))
(println (string-concat "Group A mean: " (mean group-a)))
(assert-equal 30 (mean group-b))
(println (string-concat "Group B mean: " (mean group-b)))

;; Combine groups for comparison
(define all-values (c group-a group-b))
(println (string-concat "\nCombined range: " ((:: base range) all-values)))
(println (string-concat "Combined quantiles: " ((:: stats quantile) all-values)))

;; ============================================================================
;; Using R's seq and rep functions
;; ============================================================================

(println "\n=== Sequences and Repetition ===\n")

;; Create sequences
(define seq-1-10 (seq 1 10))
(assert-equal (list 1 2 3 4 5 6 7 8 9 10) (as.list seq-1-10))
(println (string-concat "Sequence 1-10: " seq-1-10))

(define seq-by-2 (seq 0 20 2))
(assert-equal (list 0 2 4 6 8 10 12 14 16 18 20) (as.list seq-by-2))
(println (string-concat "Even numbers 0-20: " seq-by-2))

;; Repeat values
(define repeated (rep 5 10))
(assert-equal (list 5 5 5 5 5 5 5 5 5 5) (as.list repeated))
(println (string-concat "Repeat 5 ten times: " repeated))

;; ============================================================================
;; Combining Arl and R for Data Processing
;; ============================================================================

(println "\n=== Hybrid Processing ===\n")

;; Generate data in R
(define raw-data ((:: stats rnorm) 20 50 10))

;; Convert to list for Arl processing
(define data-list (as.list raw-data))

;; Process with Arl functions
(define filtered (filter (lambda (x) (> x 50)) data-list))
(define squared (map (lambda (x) (* x x)) filtered))

(println (string-concat "Values > 50: " filtered))
(println (string-concat "Squared: " squared))

;; Convert back to R vector for R functions
(define result-vec (unlist squared))
(println (string-concat "Mean of squared values: " (mean result-vec)))

;; ============================================================================
;; Using keyword arguments (R named arguments)
;; ============================================================================

(println "\n=== Keyword Arguments ===\n")

;; R functions can be called with named arguments using keywords
(println "Creating sequences with named arguments:")
(define seq-named (seq :from 1 :to 10 :by 2))
(assert-equal (list 1 3 5 7 9) (as.list seq-named))
(println (string-concat "seq(from=1, to=10, by=2): " seq-named))

;; ============================================================================
;; Data Aggregation Example
;; ============================================================================

(println "\n=== Data Aggregation ===\n")

;; Sample transaction data
(define transactions
  (list
   (dict :id 1 :amount 100 :category "food")
   (dict :id 2 :amount 50 :category "transport")
   (dict :id 3 :amount 75 :category "food")
   (dict :id 4 :amount 200 :category "housing")
   (dict :id 5 :amount 30 :category "transport")))

(println "Sample transactions:")
(println transactions)

;; Extract all amounts
(define amounts (map (lambda (t) (get "amount" t)) transactions))
(assert-equal (list 100 50 75 200 30) amounts)
(println (string-concat "\nAll amounts: " amounts))

;; Calculate total
(define total (reduce + amounts))
(assert-equal 455 total)
(println (string-concat "Total spent: $" total))

;; Filter food transactions
(define food-trans (filter (lambda (t)
                             (= (get "category" t) "food"))
                           transactions))
(assert-equal 2 (length food-trans))
(println (string-concat "\nFood transactions: " (length food-trans) " items"))

(define food-total (reduce + (map (lambda (t) (get "amount" t))
                                  food-trans)))
(assert-equal 175 food-total)
(println (string-concat "Food total: $" food-total))

(println "\nExample complete!")
