-
Notifications
You must be signed in to change notification settings - Fork 67
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Adds split functions for sequence types including lists, vectors, seqs and strings #1083
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -241,11 +241,11 @@ | |
(define (nth-cdr n l) | ||
"Returns the nth-cdr of a list." | ||
(cond ((null? l) | ||
Nil) | ||
((arith:zero? n) | ||
l) | ||
(True | ||
(nth-cdr (arith:1- n) (cdr l))))) | ||
Nil) | ||
((arith:zero? n) | ||
l) | ||
(True | ||
(nth-cdr (arith:1- n) (cdr l))))) | ||
|
||
(declare elemIndex (Eq :a => :a -> List :a -> Optional UFix)) | ||
(define (elemIndex x xs) | ||
|
@@ -604,13 +604,6 @@ | |
(any f xs))) | ||
((Nil) False))) | ||
|
||
(declare split (Char -> String -> (List String))) | ||
(define (split c str) | ||
(lisp (List String) (c str) | ||
(cl:let ((split-chars (cl:list c))) | ||
(cl:declare (cl:dynamic-extent split-chars)) | ||
(uiop:split-string str :separator split-chars)))) | ||
|
||
(declare perms (List :a -> (List (List :a)))) | ||
(define (perms l) | ||
"Produce all permutations of the list L." | ||
|
@@ -643,6 +636,29 @@ This function is equivalent to all size-N elements of `(COMBS L)`." | |
(map (Cons x) (combsOf (- n 1) xs)) ; combs with X | ||
(combsOf n xs))))))) ; and without x | ||
|
||
(declare split ((Eq :a) => :a -> (List :a) -> (iter:Iterator (List :a)))) | ||
(define (split delim xs) | ||
(let ((blocks (cell:new Nil)) | ||
(current-block (cell:new Nil)) | ||
(iter (iter:into-iter xs))) | ||
|
||
(iter:for-each! (fn (x) | ||
(cond | ||
((== x delim) | ||
(cell:push! blocks (reverse (cell:read current-block))) | ||
(cell:write! current-block nil) | ||
Unit) | ||
(True | ||
(cell:push! current-block x) | ||
Unit))) | ||
iter) | ||
|
||
(unless (null? (cell:read current-block)) | ||
(cell:push! blocks (reverse (cell:read current-block))) | ||
Unit) | ||
|
||
(iter:into-iter (reverse (cell:read blocks))))) | ||
|
||
;; | ||
;; Instances | ||
;; | ||
|
@@ -764,5 +780,7 @@ This function is equivalent to all size-N elements of `(COMBS L)`." | |
(define-instance (Default (List :a)) | ||
(define (default) Nil))) | ||
|
||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ? |
||
|
||
#+sb-package-locks | ||
(sb-ext:lock-package "COALTON-LIBRARY/LIST") |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,7 +10,8 @@ | |
(#:optional #:coalton-library/optional) | ||
(#:cell #:coalton-library/cell) | ||
(#:vector #:coalton-library/vector) | ||
(#:iter #:coalton-library/iterator)) | ||
(#:iter #:coalton-library/iterator) | ||
(#:list #:coalton-library/list)) | ||
(:export | ||
#:Seq | ||
#:new | ||
|
@@ -21,6 +22,7 @@ | |
#:put | ||
#:empty? | ||
#:conc | ||
#:split | ||
#:make)) | ||
|
||
(in-package #:coalton-library/seq) | ||
|
@@ -60,7 +62,7 @@ | |
UFix ; height | ||
UFix ; cached full subtree size | ||
(vector:Vector UFix) ; cumulative size table | ||
(vector:Vector (Seq :a))) ; subtrees | ||
(vector:Vector (Seq :a))) ; subtrees | ||
(LeafArray (vector:Vector :a))) | ||
|
||
(declare new (types:RuntimeRepr :a => Unit -> Seq :a)) | ||
|
@@ -139,14 +141,14 @@ a new `Seq` instance." | |
(do | ||
((Tuple leaf newsub) <- (pop (vector:last-unsafe sts))) | ||
(let newsts = (vector:copy sts)) | ||
(let newcst = (vector:copy cst)) | ||
(let last-idx = (- (vector:length cst) 1)) | ||
(let seq-size = (size seq)) | ||
(let newcst = (vector:copy cst)) | ||
(let last-idx = (- (vector:length cst) 1)) | ||
(let seq-size = (size seq)) | ||
(pure | ||
(cond | ||
;; this was the only thing left in seq | ||
((== 1 seq-size) | ||
(Tuple leaf newsub)) ; newsub is empty | ||
(Tuple leaf newsub)) ; newsub is empty | ||
|
||
;; the seq was exactly one larger than the subtree size | ||
;; for the current height, this means we can reduce the tree height | ||
|
@@ -164,7 +166,7 @@ a new `Seq` instance." | |
(vector:set! last-idx newsub newsts) | ||
(Tuple leaf (RelaxedNode h fss newcst newsts))))))))) | ||
|
||
(define (conc left right) | ||
(define (conc left right) | ||
"Concatenate two `Seq`s" | ||
(cond | ||
((empty? left) right) | ||
|
@@ -207,6 +209,30 @@ a new `Seq` instance." | |
(rebalance-branches | ||
(fold <> (butlast lsubts) (make-list nsubts (butfirst rsubts)))))))))))) | ||
|
||
(declare split ((Eq :a) (types:RuntimeRepr :a) => :a -> (Seq :a) -> (iter:Iterator (Seq :a)))) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This implementation needs to be streaming. The current version won't work with infinite iterators. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm confused about this- I don't believe There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Or do you mean simply that I should also define split for |
||
(define (split delim xs) | ||
(let ((blocks (cell:new Nil)) | ||
(current-block (cell:new (new))) | ||
(iter (iter:into-iter xs))) | ||
|
||
(iter:for-each! | ||
(fn (x) | ||
(cond | ||
((== x delim) | ||
(cell:push! blocks (cell:read current-block)) | ||
(cell:write! current-block (new)) | ||
Unit) | ||
(True | ||
(cell:write! current-block (push (cell:read current-block) x)) | ||
Unit))) | ||
iter) | ||
|
||
(unless (empty? (cell:read current-block)) | ||
(cell:push! blocks (cell:read current-block)) | ||
Unit) | ||
|
||
(iter:into-iter (list:reverse (cell:read blocks))))) | ||
|
||
;; | ||
;; Instances | ||
;; | ||
|
@@ -253,6 +279,8 @@ a new `Seq` instance." | |
(iter:zip! (iter:into-iter a) | ||
(iter:into-iter b))))))) | ||
|
||
|
||
|
||
;; | ||
;; Helpers | ||
;; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,21 +11,23 @@ | |
#:Vector) | ||
(:local-nicknames | ||
(#:cell #:coalton-library/cell) | ||
(#:iter #:coalton-library/iterator)) | ||
(#:iter #:coalton-library/iterator) | ||
(#:list #:coalton-library/list)) | ||
(:export | ||
#:concat | ||
#:reverse | ||
#:length | ||
#:substring | ||
#:split | ||
#:bisect | ||
#:strip-prefix | ||
#:strip-suffix | ||
#:parse-int | ||
#:ref | ||
#:ref-unchecked | ||
#:substring-index | ||
#:substring? | ||
#:chars)) | ||
#:chars | ||
#:split)) | ||
|
||
|
||
(in-package #:coalton-library/string) | ||
|
@@ -65,9 +67,9 @@ | |
(lisp String (real-start real-end str) | ||
(cl:subseq str real-start real-end)))) | ||
|
||
(declare split (UFix -> String -> (Tuple String String))) | ||
(define (split n str) | ||
"Splits a string into a head and tail at the nth index." | ||
(declare bisect (UFix -> String -> (Tuple String String))) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think |
||
(define (bisect n str) | ||
"Bisects a string into a head and tail at the nth index." | ||
(Tuple (substring str 0 n) | ||
(substring str n (length str)))) | ||
|
||
|
@@ -134,6 +136,12 @@ does not have that suffix." | |
(define (chars str) | ||
"Returns an iterator over the characters in `str`." | ||
(iter:into-iter str)) | ||
|
||
(declare split (Char -> String -> (List String))) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
(define (split ch str) | ||
"Splits a string with a specified single-character delimeter." | ||
(map (fn (x) (the String (into x))) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not for this PR, but I'd love the Lisp-equivalent of
|
||
(iter:collect! (list:split ch (the (List Char) (into str)))))) | ||
|
||
;; | ||
;; Instances | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -32,6 +32,7 @@ | |
#:last | ||
#:last-unsafe | ||
#:extend! | ||
#:split | ||
#:find-elem | ||
#:append | ||
#:swap-remove! | ||
|
@@ -247,6 +248,24 @@ | |
iter) | ||
Unit) | ||
|
||
(declare split ((Eq :a) => :a -> (Vector :a) -> (iter:Iterator (Vector :a)))) | ||
Izaakwltn marked this conversation as resolved.
Show resolved
Hide resolved
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. split-by here too |
||
(define (split delim v) | ||
"Splits a vector according to a delimiter. Returns an iterator of vectors." | ||
(let fragments = (new)) | ||
(let current-fragment = (new)) | ||
(for i in (iter:up-to (length v)) | ||
(let ((elt (index-unsafe i v))) | ||
(cond ((== elt delim) | ||
(push! (copy current-fragment) fragments) | ||
(clear! current-fragment)) | ||
(True | ||
(push! elt current-fragment) | ||
Unit)))) | ||
(while (not (empty? current-fragment)) | ||
(push! (copy current-fragment) fragments) | ||
(clear! current-fragment)) | ||
(iter:into-iter fragments)) | ||
|
||
;; | ||
;; Instances | ||
;; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
(cl:in-package #:coalton-native-tests) | ||
|
||
(coalton-toplevel | ||
(define *split-path* "wow/ok/dir/file.txt") | ||
|
||
(define *split-path-undotted* (make-list | ||
(make-list #\w #\o #\w #\/ #\o #\k #\/ #\d #\i #\r #\/ #\f #\i #\l #\e) | ||
(make-list #\t #\x #\t))) | ||
|
||
(define *split-path-unslashed* (make-list | ||
(make-list #\w #\o #\w) | ||
(make-list #\o #\k) | ||
(make-list #\d #\i #\r) | ||
(make-list #\f #\i #\l #\e #\. #\t #\x #\t)))) | ||
|
||
;;; | ||
;;; splitting lists | ||
;;; | ||
|
||
(define-test split-list () | ||
(is (== (iter:collect! (list:split #\. (iter:collect! (string:chars *split-path*)))) *split-path-undotted*)) | ||
(is (== (iter:collect! (list:split #\/ (iter:collect! (string:chars *split-path*)))) *split-path-unslashed*)) | ||
(is (== (iter:collect! (list:split 2 (make-list 1 2 3 4 2 5 2))) (make-list (make-list 1) | ||
(make-list 3 4) | ||
(make-list 5)))) | ||
(is (== (iter:collect! (list:split #\A (iter:collect! (string:chars "BANANA")))) | ||
(make-list (make-list #\B) | ||
(make-list #\N) | ||
(make-list #\N))))) | ||
|
||
;;; | ||
;;; splitting vectors | ||
;;; | ||
|
||
|
||
(define-test split-vector () | ||
(is (== (iter:collect! (vector:split #\. (list->vec (iter:collect! (string:chars *split-path*))))) | ||
(map list->vec *split-path-undotted*))) | ||
(is (== (iter:collect! (vector:split #\/ (list->vec (iter:collect! (string:chars *split-path*))))) | ||
(map list->vec *split-path-unslashed*)))) | ||
|
||
;;; | ||
;;; splitting vector | ||
;;; | ||
|
||
|
||
(coalton-toplevel | ||
|
||
(define (seq-num-list) | ||
(the (seq:Seq Integer) (iter:collect! (iter:up-to 10))))) | ||
|
||
(define-test split-seq () | ||
(is (== (the (List (seq:Seq Integer)) | ||
(iter:collect! (seq:split 5 (seq-num-list)))) | ||
(make-list (the (seq:Seq Integer) (iter:collect! (iter:up-to 5))) | ||
(the (seq:Seq Integer) (iter:collect! (map (fn (x) (+ x 6)) (iter:up-to 4)))))))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we have
split-by
which doesn't need Eq, andsplit
implemented in terms of it?