diff --git a/goldfish/liii/list.scm b/goldfish/liii/list.scm index dd1781d6..6e985211 100644 --- a/goldfish/liii/list.scm +++ b/goldfish/liii/list.scm @@ -42,6 +42,8 @@ flat-map list-null? list-not-null? not-null-list? length=? length>? length>=? flatten + ; Scala-style take/drop with boundary tolerance + list-take list-drop list-take-right list-drop-right ) ;export (import (srfi srfi-1) (srfi srfi-13) @@ -86,6 +88,58 @@ (define flat-map append-map) + (define (list-take lst n) + (unless (list? lst) + (type-error "list-take: first argument must be a list" lst) + ) ;unless + (unless (integer? n) + (type-error "list-take: second argument must be an integer" n) + ) ;unless + (cond ((< n 0) '()) + ((>= n (length lst)) lst) + (else (take lst n)) + ) ;cond + ) ;define + + (define (list-drop lst n) + (unless (list? lst) + (type-error "list-drop: first argument must be a list" lst) + ) ;unless + (unless (integer? n) + (type-error "list-drop: second argument must be an integer" n) + ) ;unless + (cond ((< n 0) lst) + ((>= n (length lst)) '()) + (else (drop lst n)) + ) ;cond + ) ;define + + (define (list-take-right lst n) + (unless (list? lst) + (type-error "list-take-right: first argument must be a list" lst) + ) ;unless + (unless (integer? n) + (type-error "list-take-right: second argument must be an integer" n) + ) ;unless + (cond ((< n 0) '()) + ((>= n (length lst)) lst) + (else (take-right lst n)) + ) ;cond + ) ;define + + (define (list-drop-right lst n) + (unless (list? lst) + (type-error "list-drop-right: first argument must be a list" lst) + ) ;unless + (unless (integer? n) + (type-error "list-drop-right: second argument must be an integer" n) + ) ;unless + (cond ((< n 0) lst) + ((>= n (length lst)) '()) + (else (drop-right lst n)) + ) ;cond + ) ;define + (define (not-null-list? l) (cond ((pair? l) (or (null? (cdr l)) (pair? (cdr l)))) diff --git a/goldfish/liii/rich-list.scm b/goldfish/liii/rich-list.scm index 890da058..7fb46ca9 100644 --- a/goldfish/liii/rich-list.scm +++ b/goldfish/liii/rich-list.scm @@ -224,121 +224,25 @@ (define (%take x . args) (chain-apply args - (begin - (define (scala-take data n) - (unless (list? data) - (type-error - (format #f "In funtion #<~a ~a>: argument *~a* must be *~a*! **Got ~a**" - scala-take '(data n) 'data "list" (object->string data) - ) ;format - ) ;type-error - ) ;unless - (unless (integer? n) - (type-error - (format #f "In funtion #<~a ~a>: argument *~a* must be *~a*! **Got ~a**" - scala-take '(data n) 'n "integer" (object->string n) - ) ;format - ) ;type-error - ) ;unless - - (cond ((< n 0) '()) - ((>= n (length data)) data) - (else (take data n)) - ) ;cond - ) ;define - - (rich-list (scala-take data x)) - ) ;begin + (rich-list (list-take data x)) ) ;chain-apply ) ;define (define (%drop x . args) (chain-apply args - (begin - (define (scala-drop data n) - (unless (list? data) - (type-error - (format #f "In funtion #<~a ~a>: argument *~a* must be *~a*! **Got ~a**" - scala-drop '(data n) 'data "list" (object->string data) - ) ;format - ) ;type-error - ) ;unless - (unless (integer? n) - (type-error - (format #f "In funtion #<~a ~a>: argument *~a* must be *~a*! **Got ~a**" - scala-drop '(data n) 'n "integer" (object->string n) - ) ;format - ) ;type-error - ) ;unless - - (cond ((< n 0) data) - ((>= n (length data)) '()) - (else (drop data n)) - ) ;cond - ) ;define - - (rich-list (scala-drop data x)) - ) ;begin + (rich-list (list-drop data x)) ) ;chain-apply ) ;define (define (%take-right x . args) (chain-apply args - (begin - (define (scala-take-right data n) - (unless (list? data) - (type-error - (format #f "In funtion #<~a ~a>: argument *~a* must be *~a*! **Got ~a**" - scala-take-right '(data n) 'data "list" (object->string data) - ) ;format - ) ;type-error - ) ;unless - (unless (integer? n) - (type-error - (format #f "In funtion #<~a ~a>: argument *~a* must be *~a*! **Got ~a**" - scala-take-right '(data n) 'n "integer" (object->string n) - ) ;format - ) ;type-error - ) ;unless - - (cond ((< n 0) '()) - ((>= n (length data)) data) - (else (take-right data n)) - ) ;cond - ) ;define - - (rich-list (scala-take-right data x)) - ) ;begin + (rich-list (list-take-right data x)) ) ;chain-apply ) ;define (define (%drop-right x . args) (chain-apply args - (begin - (define (scala-drop-right data n) - (unless (list? data) - (type-error - (format #f "In funtion #<~a ~a>: argument *~a* must be *~a*! **Got ~a**" - scala-drop-right '(data n) 'data "list" (object->string data) - ) ;format - ) ;type-error - ) ;unless - (unless (integer? n) - (type-error - (format #f "In funtion #<~a ~a>: argument *~a* must be *~a*! **Got ~a**" - scala-drop-right '(data n) 'n "integer" (object->string n) - ) ;format - ) ;type-error - ) ;unless - - (cond ((< n 0) data) - ((>= n (length data)) '()) - (else (drop-right data n)) - ) ;cond - ) ;define - - (rich-list (scala-drop-right data x)) - ) ;begin + (rich-list (list-drop-right data x)) ) ;chain-apply ) ;define diff --git a/goldfish/liii/rich-vector.scm b/goldfish/liii/rich-vector.scm index ac73e530..efb5a164 100644 --- a/goldfish/liii/rich-vector.scm +++ b/goldfish/liii/rich-vector.scm @@ -16,7 +16,8 @@ (define-library (liii rich-vector) (import (liii string) (liii hash-table) (liii sort) (liii list) (liii vector) (liii oop) (srfi srfi-8) - (rename (liii rich-option) (rich-option option))) + (rename (liii rich-option) (rich-option option)) + ) ;import (export rich-vector) (begin @@ -219,74 +220,26 @@ ) ;define (define (%take n . args) - (define (scala-take data n) - (cond - ((< n 0) (vector)) - ((>= n (vector-length data)) data) - (else - (let ((new-vec (make-vector n))) - (do ((i 0 (+ i 1))) - ((>= i n) new-vec) - (vector-set! new-vec i (vector-ref data i)) - ) ;do - ) ;let - ) ;else - ) ;cond - ) ;define - (chain-apply args - (rich-vector (scala-take data n)) + (rich-vector (vector-take data n)) ) ;chain-apply ) ;define (define (%take-right n . args) - (define (scala-take-right data n) - (let ((len (vector-length data))) - (cond - ((< n 0) (vector)) - ((>= n len) data) - (else - (let ((new-vec (make-vector n))) - (do ((i (- len n) (+ i 1)) - (j 0 (+ j 1))) - ((>= j n) new-vec) - (vector-set! new-vec j (vector-ref data i)) - ) ;do - ) ;let - ) ;else - ) ;cond - ) ;let - ) ;define - (chain-apply args - (rich-vector (scala-take-right data n)) + (rich-vector (vector-take-right data n)) ) ;chain-apply ) ;define (define (%drop n . args) - (define (scala-drop data n) - (cond - ((< n 0) data) - ((>= n (vector-length data)) (vector)) - (else (vector-copy data n)) - ) ;cond - ) ;define (chain-apply args - (rich-vector (scala-drop data n)) + (rich-vector (vector-drop data n)) ) ;chain-apply ) ;define (define (%drop-right n . args) - (define (scala-drop-right data n) - (cond - ((< n 0) data) - ((>= n (vector-length data)) (vector)) - (else (vector-copy data 0 (- (vector-length data) n))) - ) ;cond - ) ;define - (chain-apply args - (rich-vector (scala-drop-right data n)) + (rich-vector (vector-drop-right data n)) ) ;chain-apply ) ;define diff --git a/goldfish/liii/vector.scm b/goldfish/liii/vector.scm index 7b1b280b..4ada3423 100644 --- a/goldfish/liii/vector.scm +++ b/goldfish/liii/vector.scm @@ -34,7 +34,9 @@ vector-swap! vector-reverse! vector-cumulate reverse-list->vector vector= vector-contains? ; Liii Extras - vector-filter + vector-filter vector-contains? + ; Scala-style take/drop with boundary tolerance + vector-take vector-drop vector-take-right vector-drop-right ) ;export (begin @@ -66,6 +68,65 @@ ) ;let ) ;define + (define (vector-take vec n) + (unless (vector? vec) + (type-error "vector-take: first argument must be a vector" vec) + ) ;unless + (unless (integer? n) + (type-error "vector-take: second argument must be an integer" n) + ) ;unless + (let ((len (vector-length vec))) + (cond ((< n 0) (vector)) + ((>= n len) vec) + (else (vector-copy vec 0 n)) + ) ;cond + ) ;let + ) ;define + + (define (vector-drop vec n) + (unless (vector? vec) + (type-error "vector-drop: first argument must be a vector" vec) + ) ;unless + (unless (integer? n) + (type-error "vector-drop: second argument must be an integer" n) + ) ;unless + (let ((len (vector-length vec))) + (cond ((< n 0) vec) + ((>= n len) (vector)) + (else (vector-copy vec n)) + ) ;cond + ) ;let + ) ;define + + (define (vector-take-right vec n) + (unless (vector? vec) + (type-error "vector-take-right: first argument must be a vector" vec) + ) ;unless + (unless (integer? n) + (type-error "vector-take-right: second argument must be an integer" n) + ) ;unless + (let ((len (vector-length vec))) + (cond ((< n 0) (vector)) + ((>= n len) vec) + (else (vector-copy vec (- len n))) + ) ;cond + ) ;let + ) ;define + + (define (vector-drop-right vec n) + (unless (vector? vec) + (type-error "vector-drop-right: first argument must be a vector" vec) + ) ;unless + (unless (integer? n) + (type-error "vector-drop-right: second argument must be an integer" n) + ) ;unless + (let ((len (vector-length vec))) + (cond ((< n 0) vec) + ((>= n len) (vector)) + (else (vector-copy vec 0 (- len n))) + ) ;cond + ) ;let + ) ;define ) ;begin ) ;define-library diff --git a/tests/goldfish/liii/list-test.scm b/tests/goldfish/liii/list-test.scm index 326579f7..ae38f7c3 100644 --- a/tests/goldfish/liii/list-test.scm +++ b/tests/goldfish/liii/list-test.scm @@ -1735,4 +1735,143 @@ type-error 当 depth 参数既不是整数也不是 'deepest 符号时抛出。 (check-catch 'type-error (flatten '((a) () (b ()) () (c)) 'a)) (check-catch 'type-error (flatten '((a) () (b ()) () (c)) (make-vector 1 1))) +#| +list-take +Scala风格的take函数,对越界情况容忍。 + +语法 +---- +(list-take lst n) + +参数 +---- +lst : list? +源列表,从中提取元素。 + +n : integer? +要提取的元素数量。 + +返回值 +------ +list +包含指定数量元素的新列表,从原列表的开头开始计数。 + +说明 +---- +与SRFI-1的take不同,list-take对越界情况容忍: +- 当n < 0时,返回空列表 +- 当n >= 列表长度时,返回原列表 +- 否则返回前n个元素 + +错误处理 +-------- +type-error 当lst不是列表或n不是整数时抛出。 +|# + +; 基本功能测试 +(check (list-take '(1 2 3 4 5) 3) => '(1 2 3)) +(check (list-take '(1 2 3 4 5) 0) => '()) +(check (list-take '(1 2 3 4 5) 5) => '(1 2 3 4 5)) + +; 边界容忍测试(与take的主要区别) +(check (list-take '(1 2 3) -1) => '()) +(check (list-take '(1 2 3) 10) => '(1 2 3)) + +; 空列表测试 +(check (list-take '() 0) => '()) +(check (list-take '() 5) => '()) + +; 错误处理测试 +(check-catch 'type-error (list-take "not a list" 2)) +(check-catch 'type-error (list-take '(1 2 3) "not a number")) + +#| +list-drop +Scala风格的drop函数,对越界情况容忍。 + +语法 +---- +(list-drop lst n) + +说明 +---- +与SRFI-1的drop不同,list-drop对越界情况容忍: +- 当n < 0时,返回原列表 +- 当n >= 列表长度时,返回空列表 +- 否则返回去掉前n个元素后的列表 +|# + +; 基本功能测试 +(check (list-drop '(1 2 3 4 5) 3) => '(4 5)) +(check (list-drop '(1 2 3 4 5) 0) => '(1 2 3 4 5)) +(check (list-drop '(1 2 3 4 5) 5) => '()) + +; 边界容忍测试 +(check (list-drop '(1 2 3) -1) => '(1 2 3)) +(check (list-drop '(1 2 3) 10) => '()) + +; 空列表测试 +(check (list-drop '() 0) => '()) +(check (list-drop '() 5) => '()) + +; 错误处理测试 +(check-catch 'type-error (list-drop "not a list" 2)) +(check-catch 'type-error (list-drop '(1 2 3) "not a number")) + +#| +list-take-right +Scala风格的take-right函数,对越界情况容忍。 + +说明 +---- +与SRFI-1的take-right不同,list-take-right对越界情况容忍: +- 当n < 0时,返回空列表 +- 当n >= 列表长度时,返回原列表 +- 否则返回后n个元素 +|# + +; 基本功能测试 +(check (list-take-right '(1 2 3 4 5) 3) => '(3 4 5)) +(check (list-take-right '(1 2 3 4 5) 0) => '()) +(check (list-take-right '(1 2 3 4 5) 5) => '(1 2 3 4 5)) + +; 边界容忍测试 +(check (list-take-right '(1 2 3) -1) => '()) +(check (list-take-right '(1 2 3) 10) => '(1 2 3)) + +; 空列表测试 +(check (list-take-right '() 0) => '()) + +; 错误处理测试 +(check-catch 'type-error (list-take-right "not a list" 2)) +(check-catch 'type-error (list-take-right '(1 2 3) "not a number")) + +#| +list-drop-right +Scala风格的drop-right函数,对越界情况容忍。 + +说明 +---- +与SRFI-1的drop-right不同,list-drop-right对越界情况容忍: +- 当n < 0时,返回原列表 +- 当n >= 列表长度时,返回空列表 +- 否则返回去掉后n个元素后的列表 +|# + +; 基本功能测试 +(check (list-drop-right '(1 2 3 4 5) 3) => '(1 2)) +(check (list-drop-right '(1 2 3 4 5) 0) => '(1 2 3 4 5)) +(check (list-drop-right '(1 2 3 4 5) 5) => '()) + +; 边界容忍测试 +(check (list-drop-right '(1 2 3) -1) => '(1 2 3)) +(check (list-drop-right '(1 2 3) 10) => '()) + +; 空列表测试 +(check (list-drop-right '() 0) => '()) + +; 错误处理测试 +(check-catch 'type-error (list-drop-right "not a list" 2)) +(check-catch 'type-error (list-drop-right '(1 2 3) "not a number")) + (check-report) \ No newline at end of file diff --git a/tests/goldfish/liii/vector-test.scm b/tests/goldfish/liii/vector-test.scm index 75e369e4..ea7a6719 100644 --- a/tests/goldfish/liii/vector-test.scm +++ b/tests/goldfish/liii/vector-test.scm @@ -19,6 +19,7 @@ (liii vector) (liii cut) (liii base) + (liii error) (only (scheme base) let-values) ) ;import @@ -1754,5 +1755,114 @@ type-error ;; 错误处理测试 (check-catch 'type-error (vector-contains? 'not-a-vector 1)) ; 非向量参数 +#| +vector-take +Scala风格的vector-take函数,对越界情况容忍。 + +语法 +---- +(vector-take vec n) + +参数 +---- +vec : vector? +源向量,从中提取元素。 + +n : integer? +要提取的元素数量。 + +返回值 +------ +vector +包含指定数量元素的新向量,从原向量的开头开始计数。 + +说明 +---- +- 当n < 0时,返回空向量 +- 当n >= 向量长度时,返回原向量 +- 否则返回前n个元素 +|# + +; 基本功能测试 +(check (vector-take #(1 2 3 4 5) 3) => #(1 2 3)) +(check (vector-take #(1 2 3 4 5) 0) => #()) +(check (vector-take #(1 2 3 4 5) 5) => #(1 2 3 4 5)) + +; 边界容忍测试 +(check (vector-take #(1 2 3) -1) => #()) +(check (vector-take #(1 2 3) 10) => #(1 2 3)) + +; 空向量测试 +(check (vector-take #() 0) => #()) +(check (vector-take #() 5) => #()) + +; 错误处理测试 +(check-catch 'type-error (vector-take "not a vector" 2)) +(check-catch 'type-error (vector-take #(1 2 3) "not a number")) + +#| +vector-drop +Scala风格的vector-drop函数,对越界情况容忍。 +|# + +; 基本功能测试 +(check (vector-drop #(1 2 3 4 5) 3) => #(4 5)) +(check (vector-drop #(1 2 3 4 5) 0) => #(1 2 3 4 5)) +(check (vector-drop #(1 2 3 4 5) 5) => #()) + +; 边界容忍测试 +(check (vector-drop #(1 2 3) -1) => #(1 2 3)) +(check (vector-drop #(1 2 3) 10) => #()) + +; 空向量测试 +(check (vector-drop #() 0) => #()) +(check (vector-drop #() 5) => #()) + +; 错误处理测试 +(check-catch 'type-error (vector-drop "not a vector" 2)) +(check-catch 'type-error (vector-drop #(1 2 3) "not a number")) + +#| +vector-take-right +Scala风格的vector-take-right函数,对越界情况容忍。 +|# + +; 基本功能测试 +(check (vector-take-right #(1 2 3 4 5) 3) => #(3 4 5)) +(check (vector-take-right #(1 2 3 4 5) 0) => #()) +(check (vector-take-right #(1 2 3 4 5) 5) => #(1 2 3 4 5)) + +; 边界容忍测试 +(check (vector-take-right #(1 2 3) -1) => #()) +(check (vector-take-right #(1 2 3) 10) => #(1 2 3)) + +; 空向量测试 +(check (vector-take-right #() 0) => #()) + +; 错误处理测试 +(check-catch 'type-error (vector-take-right "not a vector" 2)) +(check-catch 'type-error (vector-take-right #(1 2 3) "not a number")) + +#| +vector-drop-right +Scala风格的vector-drop-right函数,对越界情况容忍。 +|# + +; 基本功能测试 +(check (vector-drop-right #(1 2 3 4 5) 3) => #(1 2)) +(check (vector-drop-right #(1 2 3 4 5) 0) => #(1 2 3 4 5)) +(check (vector-drop-right #(1 2 3 4 5) 5) => #()) + +; 边界容忍测试 +(check (vector-drop-right #(1 2 3) -1) => #(1 2 3)) +(check (vector-drop-right #(1 2 3) 10) => #()) + +; 空向量测试 +(check (vector-drop-right #() 0) => #()) + +; 错误处理测试 +(check-catch 'type-error (vector-drop-right "not a vector" 2)) +(check-catch 'type-error (vector-drop-right #(1 2 3) "not a number")) + (check-report)