%export "random"
        process statistics count
        doMonteCarlo do_MC_on_battery
        build_up_statistics
        mean provide_mean
%include "random"

count == int
int == num

process * == sequence -> *
frequency_table * == [(*,count)]
statistics * == (frequency_table *, count) || ie, total given explicitly





doMonteCarlo :: (* -> * -> bool) -> process * -> real -> [statistics *]
|| lesseq function -> process -> input for battery_of_test_sequences
||  -> accumulating statistics
|| NOTE: input for battery_of_test_sequences should be "irrational"
||  (see its comment)
  doMonteCarlo lesseq p r
    = do_MC_on_battery lesseq p (battery_of_test_sequences r)

do_MC_on_battery :: (* -> * -> bool)
                      -> process * -> [sequence] -> [statistics *]
|| lesseq function -> process -> actual battery of test sequences
||  -> accumulating statistics
  do_MC_on_battery lesseq p s
    = build_up_statistics lesseq (map p s)





mean :: statistics num -> num
|| computes the mean of the statistics, assuming the alleged total (second
||  component) is truthful. NOTE: for some applications, using this is
||  wildly inappropriate!
  mean (freqs,total) = sum (map pair_product freqs) / total, total~=0
                     = error "mean of no data is absurd", total=0
                       where
                       pair_product (x,y) = x*y

provide_mean :: statistics num -> (statistics num, num)
|| attaches the mean as shown in the type declaration. NOTE: uses mean, so
|| again the total must be truthful, and again the whole thing is often
|| wildly inappropriate! (See comment for mean.)
  provide_mean stats = (stats, mean stats)








build_up_statistics :: (* -> * -> bool) -> [*] -> [statistics *]
  build_up_statistics lesseq results = start_from_here lesseq ([],0) results

start_from_here :: (* -> * -> bool) -> statistics * -> [*] -> [statistics *]
  start_from_here lesseq here results
    = [here], results=[]
    = here : (start_from_here
              lesseq
              (insert_result lesseq (hd results) here)
              (tl results)
             ), otherwise

insert_result :: (* -> * -> bool) -> * -> statistics * -> statistics *
|| lesseq function -> new result -> statistics so far -> update
  insert_result lesseq a (freqs,total)
    = (update_frequency_table lesseq a freqs, total+1)

update_frequency_table :: (* -> * -> bool) -> * -> frequency_table *
                            -> frequency_table *
|| lesseq function -> new result -> frequency table so far -> update
  update_frequency_table lesseq a [] = [(a,1)]
  update_frequency_table lesseq a ((b,n):rest)
    = (b,n) : update_frequency_table lesseq a rest, ~(a $lesseq b)
    = (b,n+1):rest, a=b
    = (a,1):(b,n):rest, otherwise
