diff --git a/lib/std/core/list.kk b/lib/std/core/list.kk index 27a1c843f..2ff500037 100644 --- a/lib/std/core/list.kk +++ b/lib/std/core/list.kk @@ -328,9 +328,13 @@ pub fun filter( xs : list, pred : a -> e bool ) : e list // Remove those elements of a list that satisfy the given predicate `pred`. // For example: `remove([1,2,3],odd?) == [2]` -pub fun remove( xs : list, pred : a -> e bool ) : e list +pub fun pred/remove( xs : list, pred : a -> e bool ) : e list xs.filter( fn(x) !pred(x) ) +// Remove those elements of a list that are equal to `value`. +pub fun eq/remove( xs : list, value : a, ?(==) : (a,a) -> e bool ) : e list + xs.filter( fn(x) !(x==value) ) + // Partition a list in two lists where the first list contains // those elements that satisfy the given predicate `pred`. // For example: `partition([1,2,3],odd?) == ([1,3],[2])` @@ -353,6 +357,12 @@ pub fun filter-map( xs : list, pred : a -> e maybe ) : e list Nothing -> xx.filter-map(pred) Just(y) -> Cons(y,xx.filter-map(pred)) +// Does the list contain the given value? +pub fun contains( xs : list, value : a, ?(==) : (a,a) -> e bool ) : e bool + match xs + Cons(x,xx) -> if x==value then True else xx.contains(value) + Nil -> False + // Find the first element satisfying some predicate pub fun find( xs : list, pred : a -> e bool ) : e maybe xs.foreach-while fn(x) @@ -363,10 +373,14 @@ pub fun find-maybe( xs : list, pred : a -> e maybe ) : e maybe xs.foreach-while(pred) // Lookup the first element satisfying some predicate -pub fun lookup( xs : list<(a,b)>, pred : a -> e bool ) : e maybe - xs.foreach-while fn(kv) - if pred(kv.fst) then Just(kv.snd) else Nothing +pub fun pred/lookup( xs : list<(a,b)>, pred : a -> e bool ) : e maybe + xs.foreach-while fn((fst, snd)) + if pred(fst) then Just(snd) else Nothing +// Lookup the value for a given key +pub fun eq/lookup( xs : list<(a,b)>, key : a, ?(==) : (a,a) -> e bool ) : e maybe + xs.foreach-while fn((fst, snd)) + if fst==key then Just(snd) else Nothing // Convert a `:maybe` type to a list type. pub fun maybe/list( m : maybe ) : list @@ -381,9 +395,17 @@ fun index-of-acc( xs : list, pred : a -> e bool, idx : int ) : e int // Returns the index of the first element where `pred` holds, or `-1` if no such element exists. -pub fun index-of( xs : list, pred : a -> e bool ) : e int +pub fun pred/index-of( xs : list, pred : a -> e bool ) : e int index-of-acc( xs, pred, 0 ) +// Returns the index of the first element equal to `value` or `-1` if no such element exists. +pub fun eq/index-of( xs : list, value : a, ?(==) : (a,a) -> e bool ) : e maybe + fun recur( ys, idx ) + match ys + Cons(y,yy) -> if y==value then Just(idx) else recur(yy,idx+1) + Nil -> Nothing + recur(xs,0) + // Invoke `action` for each element of a list pub fun foreach( xs : list, action : (a) -> e () ) : e () match xs diff --git a/lib/std/core/show.kk b/lib/std/core/show.kk index 3356d1cc5..989e80ea0 100644 --- a/lib/std/core/show.kk +++ b/lib/std/core/show.kk @@ -16,6 +16,7 @@ import std/core/char import std/core/string import std/core/sslice import std/core/list +import std/core/vector // ---------------------------------------------------------------------------- @@ -69,4 +70,6 @@ pub noinline fun string/show( s : string ) : string pub fun sslice/show( s : sslice ) : string s.string.show - +// Show a vector as a string +pub fun vector/show( v : vector, ?show: a -> e string ) : e string + "[" ++ v.map(show).join(",") ++ "]" \ No newline at end of file diff --git a/lib/std/core/vector.kk b/lib/std/core/vector.kk index d68e44c72..fa960d888 100644 --- a/lib/std/core/vector.kk +++ b/lib/std/core/vector.kk @@ -22,6 +22,8 @@ extern import // ---------------------------------------------------------------------------- // Vectors // ---------------------------------------------------------------------------- +// TODO: Consider in-place updates when reference count is 1 throughout! +// Also, start benchmarking // Return the element at position `index` in vector `v` without bounds check! inline extern unsafe-idx( ^v : vector, index : ssize_t ) : total a @@ -132,6 +134,160 @@ pub fun map( v : vector, f : a -> e b ) : e vector unsafe-assign(w,i,f(x)) w +// Apply a function `f` to each element in a vector `v` +pub fun map-indexed(v : vector, f: (int, a) -> e b): e vector + val w = unsafe-vector(v.length.ssize_t) + v.foreach-indexedz fn(i,x) + unsafe-assign(w,i,f(i.int, x)) + w + +// Fold over a vector from the start, accumulating a result +pub fun foldl( v : vector, initial : b, f : (b,a) -> e b ) : e b + val length = v.lengthz + fun loop(i, acc) + if i < length then + val acc2 = f(acc, v.unsafe-idx(i)) + loop(i.incr.pretend-decreasing, acc2) + else acc + loop(0.ssize_t, initial) + +// Fold over a vector from the end, accumulating a result +pub fun foldr( v : vector, initial : b, f : (a,b) -> e b ) : e b + val length = v.lengthz + fun loop(i, acc) + if i >= 0.ssize_t then + val acc2 = f(v.unsafe-idx(i), acc) + loop(i.decr.pretend-decreasing, acc2) + else acc + loop(length.decr, initial) + +// Zip two vectors into a vector of pairs. +pub fun zip( v1 : vector, v2 : vector ) : vector<(a,b)> + val l1 = v1.lengthz + val l2 = v2.lengthz + val l = if l1 <= l2 then l1 else l2 + val w = unsafe-vector(l) + forz( l ) fn(i) + unsafe-assign(w,i,(v1.unsafe-idx(i), v2.unsafe-idx(i))) + w + +// Zip two vectors using a function `f` to combine elements. +pub fun zip-with( v1 : vector, v2 : vector, f : (a,b) -> c ) : vector + val l1 = v1.lengthz + val l2 = v2.lengthz + val l = if l1 <= l2 then l1 else l2 + val w = unsafe-vector(l) + forz( l ) fn(i) + unsafe-assign(w,i,f(v1.unsafe-idx(i), v2.unsafe-idx(i))) + w + +// Zip two vectors using a function `f` to combine elements. +// The current index is passed as the first argument to `f`. +pub fun zip-with-indexed( v1 : vector, v2 : vector, f : (int,a,b) -> c ) : vector + val l1 = v1.lengthz + val l2 = v2.lengthz + val l = if l1 <= l2 then l1 else l2 + val w = unsafe-vector(l) + forz( l ) fn(i) + unsafe-assign(w,i,f(i.int, v1.unsafe-idx(i), v2.unsafe-idx(i))) + w + +// Equality of vectors +pub fun vector/(==)(v1 : vector, v2: vector, ?(==): (a, a) -> e bool): e bool + val l = v1.lengthz + if l != v2.lengthz then + False + else + val eq = for-whilez(l) fn(i) + // Found a difference can end iteration and return False immediately + if !(v1.unsafe-idx(i) == v2.unsafe-idx(i)) then Just(()) + else Nothing + match eq + Just() -> False + Nothing -> True + +// In-equality of vectors (specialized for performance) +pub fun vector/(!=)(v1 : vector, v2: vector, ?(==): (a, a) -> e bool): e bool + val l = v1.lengthz + if l != v2.lengthz then + True + else + val eq = for-whilez(l) fn(i) + // Found a difference can end iteration and return True immediately + if !(v1.unsafe-idx(i) == v2.unsafe-idx(i)) then Just(()) + else Nothing + match eq + Just() -> True + Nothing -> False + +// Take the first `n` elements from a vector. +pub fun take( v : vector, ^n : int ) : vector + val len = v.lengthz + val tn = if n.ssize_t < len then n.ssize_t else len + val w = unsafe-vector(tn) + forz( tn ) fn(i) + unsafe-assign(w,i,v.unsafe-idx(i)) + w + +// Take the first `n` elements from a vector as a list. +pub fun take-list( v : vector, ^n : int ) : list + val len = v.lengthz + val tn = if n.ssize_t < len then n.ssize_t else len + fun loop(i : ssize_t, acc : ctx>) : list<_> + if i < tn then + loop(i.incr.pretend-decreasing, acc ++ ctx Cons(v.unsafe-idx(i), hole)) + else + acc ++. Nil + loop(0.ssize_t, ctx hole) + +// Drop the first `n` elements from a vector. +pub fun drop( v : vector, ^n : int ) : vector + val len = v.lengthz + val ns = n.ssize_t + val dn = if ns < 0.ssize_t then 0.ssize_t elif ns < len then ns else len + val newlen = len - dn + val w = unsafe-vector(newlen) + forz( newlen ) fn(i) + unsafe-assign(w,i,v.unsafe-idx(i + dn)) + w + +// Take a slice from the vector from `start` (inclusive) to `end` (exclusive). +pub fun slice( v : vector, ^start : int, ^end : int ) : vector + val len = v.lengthz + val starts = start.ssize_t + val ends = end.ssize_t + val s = if starts < 0.ssize_t then 0.ssize_t elif starts > len then len else starts + val e = if ends < s then s elif ends > len then len else ends + val slen = e - s + val w = unsafe-vector(slen) + forz( slen ) fn(i) + unsafe-assign(w,i,v.unsafe-idx(i + s)) + w + +// Reverses a vector +pub fun reverse( v : vector ) : vector + val len = v.lengthz + val w = unsafe-vector(len) + forz( len ) fn(i) + unsafe-assign(w,i,v.unsafe-idx(len - i - 1.ssize_t)) + w + +// Append two vectors +pub fun append( v1 : vector, v2 : vector ) : vector + val l1 = v1.lengthz + val l2 = v2.lengthz + val l = l1 + l2 + val w = unsafe-vector(l) + forz( l1 ) fn(i) + unsafe-assign(w,i,v1.unsafe-idx(i)) + forz( l2 ) fn(i) + unsafe-assign(w,i + l1,v2.unsafe-idx(i)) + w + +// Append two vectors +pub fun vector/(++)( v1 : vector, v2 : vector ): vector + append(v1,v2) + // Convert a vector to a list. pub fun list( v : vector ) : list v.vlist @@ -177,6 +333,12 @@ fun for-whilez( n : ssize_t, action : (ssize_t) -> e maybe ) : e maybe // Minimal set of operations that we need in `std/core`. +inline fip extern ssize_t/(==) : (ssize_t,ssize_t) -> bool + inline "(#1 == #2)" + +inline fip extern ssize_t/(!=) : (ssize_t,ssize_t) -> bool + inline "(#1 != #2)" + inline fip extern ssize_t/(<=) : (ssize_t,ssize_t) -> bool inline "(#1 <= #2)" @@ -186,6 +348,9 @@ inline fip extern ssize_t/(>=) : (ssize_t,ssize_t) -> bool inline fip extern ssize_t/(<) : (ssize_t,ssize_t) -> bool inline "(#1 < #2)" +inline fip extern ssize_t/(>) : (ssize_t,ssize_t) -> bool + inline "(#1 > #2)" + inline fip extern ssize_t/(+) : (ssize_t,ssize_t) -> ssize_t inline "(#1 + #2)" js inline "((#1 + #2)|0)"