Skip to content

Commit

Permalink
Adds splittable class, split method for sequences and eq types
Browse files Browse the repository at this point in the history
  • Loading branch information
Izaakwltn committed Apr 5, 2024
1 parent f2dcbc3 commit 18a627a
Show file tree
Hide file tree
Showing 12 changed files with 195 additions and 30 deletions.
1 change: 1 addition & 0 deletions coalton.asd
Expand Up @@ -165,6 +165,7 @@
(:file "randomaccess")
(:file "cell")
(:file "iterator")
(:file "split")
(:file "optional")
(:file "result")
(:file "tuple")
Expand Down
2 changes: 1 addition & 1 deletion examples/small-coalton-programs/src/brainfold.lisp
Expand Up @@ -187,7 +187,7 @@
(let cmds = (vec:new))
(let vecs = (vec:new))
(let ((parser (fn (input-string v)
(let ((head-tail (str:split 1 input-string)))
(let ((head-tail (str:bisect 1 input-string)))
(match (fst head-tail)
("" cmds)
(">"
Expand Down
47 changes: 33 additions & 14 deletions library/list.lisp
Expand Up @@ -10,7 +10,8 @@
(:local-nicknames
(#:cell #:coalton-library/cell)
(#:iter #:coalton-library/iterator)
(#:arith #:coalton-library/math/arith))
(#:arith #:coalton-library/math/arith)
(#:split #:coalton-library/split))
(:export
#:head
#:tail
Expand Down Expand Up @@ -241,11 +242,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)
Expand Down Expand Up @@ -604,13 +605,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."
Expand Down Expand Up @@ -762,7 +756,32 @@ This function is equivalent to all size-N elements of `(COMBS L)`."
((Some a) (Cons a Nil)))))

(define-instance (Default (List :a))
(define (default) Nil)))
(define (default) Nil))

(define-instance (split:Splittable List)
(define (split: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)))))))



#+sb-package-locks
(sb-ext:lock-package "COALTON-LIBRARY/LIST")
1 change: 1 addition & 0 deletions library/prelude.lisp
Expand Up @@ -256,5 +256,6 @@
(#:hashtable #:coalton-library/hashtable)
(#:st #:coalton-library/monad/state)
(#:iter #:coalton-library/iterator)
(#:split #:coalton-library/split)
(#:sys #:coalton-library/system)))

27 changes: 26 additions & 1 deletion library/seq.lisp
Expand Up @@ -10,7 +10,9 @@
(#:optional #:coalton-library/optional)
(#:cell #:coalton-library/cell)
(#:vector #:coalton-library/vector)
(#:iter #:coalton-library/iterator))
(#:iter #:coalton-library/iterator)
(#:list #:coalton-library/list)
(#:split #:coalton-library/split))
(:export
#:Seq
#:new
Expand Down Expand Up @@ -253,6 +255,29 @@ a new `Seq` instance."
(iter:zip! (iter:into-iter a)
(iter:into-iter b)))))))

(define-instance (split:Splittable Seq)
(define (split: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))))))

;;
;; Helpers
;;
Expand Down
32 changes: 32 additions & 0 deletions library/split.lisp
@@ -0,0 +1,32 @@
(coalton-library/utils:defstdlib-package #:coalton-library/split
(:use
#:coalton
#:coalton-library/builtin
#:coalton-library/classes)
(:local-nicknames
(#:iter #:coalton-library/iterator)
(#:types #:coalton-library/types))
(:export
#:splittable
#:split))


(in-package #:coalton-library/split)

(named-readtables:in-readtable coalton:coalton)


;;;
;;; Split
;;;

(coalton-toplevel

(define-class (Splittable :seq)
"Sequence types that can be split by element equality."
(split ((Eq :a) (types:runtimerepr :a) => :a -> (:seq :a) -> (iter:iterator (:seq :a))))))



;; TODO (Maybe):
;; Add instance for Slice
20 changes: 15 additions & 5 deletions library/string.lisp
Expand Up @@ -11,12 +11,15 @@
#:Vector)
(:local-nicknames
(#:cell #:coalton-library/cell)
(#:iter #:coalton-library/iterator))
(#:iter #:coalton-library/iterator)
(#:list #:coalton-library/list)
(#:split #:coalton-library/split))
(:export
#:concat
#:reverse
#:length
#:substring
#:bisect
#:split
#:strip-prefix
#:strip-suffix
Expand All @@ -25,7 +28,8 @@
#:ref-unchecked
#:substring-index
#:substring?
#:chars))
#:chars
#:delim-split))


(in-package #:coalton-library/string)
Expand Down Expand Up @@ -65,9 +69,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)))
(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))))

Expand Down Expand Up @@ -134,6 +138,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)))
(define (split ch str)
"Splits a string with a specified single-character delimeter."
(map (fn (x) (the String (into x)))
(iter:collect! (split:split ch (the (List Char) (into str))))))

;;
;; Instances
Expand Down
17 changes: 15 additions & 2 deletions library/vector.lisp
Expand Up @@ -9,7 +9,8 @@
(#:list #:coalton-library/list)
(#:cell #:coalton-library/cell)
(#:iter #:coalton-library/iterator)
(#:ram #:coalton-library/randomaccess))
(#:ram #:coalton-library/randomaccess)
(#:split #:coalton-library/split))
(:export
#:Vector
#:new
Expand Down Expand Up @@ -348,7 +349,19 @@
vec))

(define-instance (Default (Vector :a))
(define default new)))
(define default new))

(declare list->vec (List :a -> Vector :a))
(define (list->vec x)
(into x))

(declare vec->list (Vector :a -> List :a))
(define (vec->list x)
(into x))

(define-instance (split:Splittable Vector)
(define (split:split delim v)
(map list->vec (split:split delim (vec->list v))))))

(cl:defmacro make (cl:&rest elements)
"Construct a `Vector' containing the ELEMENTS, in the order listed."
Expand Down
3 changes: 0 additions & 3 deletions tests/list-tests.lisp
Expand Up @@ -209,9 +209,6 @@
Unit)

(define-test test-combinatorics ()
(is (== (list:split #\, "one,two,three") (make-list "one" "two" "three")))
(is (== (list:split #\, "one,,three") (make-list "one" "" "three")))

(is (set== (list:perms x)
(make-list
(make-list 1 2 3)
Expand Down
3 changes: 2 additions & 1 deletion tests/package.lisp
Expand Up @@ -32,7 +32,8 @@
(#:red-black/tree #:coalton-library/ord-tree)
(#:red-black/map #:coalton-library/ord-map)
(#:result #:coalton-library/result)
(#:seq #:coalton-library/seq)))
(#:seq #:coalton-library/seq)
(#:split #:coalton-library/split)))

(in-package #:coalton-native-tests)

Expand Down
56 changes: 56 additions & 0 deletions tests/split-tests.lisp
@@ -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! (split:split #\. (iter:collect! (string:chars *split-path*)))) *split-path-undotted*))
(is (== (iter:collect! (split:split #\/ (iter:collect! (string:chars *split-path*)))) *split-path-unslashed*))
(is (== (iter:collect! (split: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! (split: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! (split:split #\. (list->vec (iter:collect! (string:chars *split-path*)))))
(map list->vec *split-path-undotted*)))
(is (== (iter:collect! (split: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! (split: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))))))))
16 changes: 13 additions & 3 deletions tests/string-tests.lisp
Expand Up @@ -19,11 +19,11 @@
(is (== (substring "foobar" 3 6)
"bar")))

(define-test string-split ()
(define-test bisect-string ()
(let str = "teststring")
(is (== (string:split 1 str)
(is (== (string:bisect 1 str)
(Tuple "t" "eststring")))
(is (== (string:split 4 str)
(is (== (string:bisect 4 str)
(Tuple "test" "string"))))

(define-test strip-fixes ()
Expand Down Expand Up @@ -76,3 +76,13 @@
(let has-empty? = (string:substring? ""))
(is (has-empty? ""))
(is (has-empty? "foo")))

(define-test string-split ()
(is (== (string:split #\, "one,two,three") (make-list "one" "two" "three")))
(is (== (string:split #\, "one,,three") (make-list "one" "" "three")))

(let path = "wow/ok/dir/file.txt")
(is (== (string:split #\. path) (make-list "wow/ok/dir/file" "txt")))
(is (== (string:split #\/ path) (make-list "wow" "ok" "dir" "file.txt")))
(is (== (string:split #\d "thisddddworks") (make-list "this" "" "" "" "works"))))

0 comments on commit 18a627a

Please sign in to comment.