-- djwutils.dx
-- Some generic utility functions
-- some of which should probably be added to the standard Dex prelude
def iterate(n: Nat, step: (a) -> a, init: a) -> Fin n => a given (a|Data) = with_state init \st. for i:(Fin n). old = get st next = step old st := next old
def unfold(n: Nat, advance: (a) -> (b, a), init: a) -> Fin n => b given (a|Data, b) = with_state init \st. for i:(Fin n). (b, a) = advance (get st) st := a b
def length(arr: n=>a) -> Nat given (a, n|Ix) = size n
def last_dumb(arr: n=>a) -> a given (a, n|Ix) = head $ reverse arr
def last(arr: n=>a) -> a given (a, n|Ix) = nind = unsafe_nat_diff (size n) 1 arr[asidx nind]
-- Not ideal instance, since likely loss of precision...
instance Parse(Float64) def parseString(str) = mf : Maybe Float = parseString str case mf of Nothing -> Nothing Just f -> Just $ f_to_f64 f
def clipv(x: a=>Float, c: Float) -> (a)=>Float given (a|Ix) = map (\xi. clip (-c, c) xi) x
def nanclip(x: a=>Float) -> (a)=>Float given (a|Ix) = map (\xi. if (isnan xi) then 0.0 else xi) x
def to_tsv(mat: (n)=>(p)=>Float) -> String given (n|Ix, p|Ix) = ms = for i j. show mat[i,j] <> "\t" concat (map (\l. l <> "\n") (map concat ms))
-- based on "lines" from the prelude...
def words(sep: Word8, source: String) -> List String = AsList(_, s) = source <> (to_list [sep]) AsList(num_words, space_ixs) = cat_maybes for i_char. if (s[i_char] == sep) then Just i_char else Nothing to_list for i_word:(Fin num_words). start = case prev_ix i_word of Nothing -> first_ix Just i -> right_post space_ixs[i] end = left_post space_ixs[i_word] post_slice s start end
def cons(x: a, xs: List a) -> List a given (a) = AsList(on, xt) = xs n = on + 1 nxt = for i:(Fin n). case (ordinal i == 0) of True -> x False -> xt[asidx (unsafe_nat_diff (ordinal i) 1)] to_list nxt
def list2tab(l: List a) -> (n)=>a given (a, n|Ix) = AsList(ll, t) = l unsafe_cast_table t
def parse_tsv(sep: Word8, input: String) -> List (List String) = AsList(_, lines) = lines input to_list $ map (\l. words sep l) lines
-- eof