srfi-1.scm 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. ;;; SRFI-1
  2. ;;; Copyright (C) 2024 David Thompson <dave@spritely.institute>
  3. ;;;
  4. ;;; Licensed under the Apache License, Version 2.0 (the "License");
  5. ;;; you may not use this file except in compliance with the License.
  6. ;;; You may obtain a copy of the License at
  7. ;;;
  8. ;;; http://www.apache.org/licenses/LICENSE-2.0
  9. ;;;
  10. ;;; Unless required by applicable law or agreed to in writing, software
  11. ;;; distributed under the License is distributed on an "AS IS" BASIS,
  12. ;;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. ;;; See the License for the specific language governing permissions and
  14. ;;; limitations under the License.
  15. ;;; Commentary:
  16. ;;;
  17. ;;; SRFI-1: List Library
  18. ;;;
  19. ;;; This module is temporary, containing just the things we need right
  20. ;;; now, until we are able to import and compile Guile's SRFI-1.
  21. ;;;
  22. ;;; Code:
  23. (define-module (srfi srfi-1)
  24. #:use-module ((hoot lists) #:select (alist-cons fold))
  25. #:export (any1
  26. any
  27. every1
  28. every
  29. fold-right
  30. filter-map
  31. find)
  32. #:re-export ((acons . alist-cons)
  33. fold
  34. iota))
  35. (define (fold-right f seed l)
  36. (fold f seed (reverse l)))
  37. (define reverse! reverse)
  38. (define (any1 pred ls)
  39. "Return the first non-false value returned by applying @var{pred} to the
  40. elements of @var{ls}, or @code{#f}."
  41. (let lp ((ls ls))
  42. (cond ((null? ls)
  43. #f)
  44. ((null? (cdr ls))
  45. (pred (car ls)))
  46. (else
  47. (or (pred (car ls)) (lp (cdr ls)))))))
  48. (define (any pred lst . lsts)
  49. "Return the first non-false value returned by applying @var{pred} to the
  50. elements of @var{lst} and @var{lsts}, or @code{#f}."
  51. (if (null? lsts) (any1 pred lst)
  52. (let lp ((ls (cons lst lsts)))
  53. (cond
  54. ((any1 null? ls) #f)
  55. ((any1 null? (map cdr ls))
  56. (apply pred (map car ls)))
  57. (else
  58. (or (apply pred (map car ls))
  59. (lp (map cdr ls))))))))
  60. (define (every1 pred lst)
  61. "Return the value of @var{pred} applied to the last element of @var{lst} if
  62. all other elements of the list satisfy @var{pred}; otherwise return @code{#f}.
  63. Return @code{#t} if @var{lst} is empty."
  64. (let lp ((l lst))
  65. (cond
  66. ((null? l) #t)
  67. ((null? (cdr l)) (pred (car l)))
  68. (else
  69. (and (pred (car l)) (lp (cdr l)))))))
  70. (define (every pred lst . lsts)
  71. "Return the value of @var{pred} applied to the last elements of @var{lst} and
  72. @var{lsts} if all other elements of the lists satisfy @var{pred}; other return
  73. @code{#f}. Return @code{#t} if any lists are empty."
  74. (if (null? lsts) (every1 pred lst)
  75. (let lp ((ls (cons lst lsts)))
  76. (cond
  77. ((any1 null? ls) #t)
  78. ((any1 null? (map cdr ls))
  79. (apply pred (map car ls)))
  80. (else
  81. (and (apply pred (map car ls))
  82. (lp (map cdr ls))))))))
  83. (define (find pred lst)
  84. "Return the first element of @var{lst} that satisfies the predicate
  85. @var{pred}, or return @code{#f} if no such element is found."
  86. (let loop ((lst lst))
  87. (and (not (null? lst))
  88. (let ((head (car lst)))
  89. (if (pred head)
  90. head
  91. (loop (cdr lst)))))))
  92. (define (filter-map proc list1 . rest)
  93. "Apply PROC to the elements of LIST1... and return a list of the
  94. results as per SRFI-1 `map', except that any #f results are omitted from
  95. the list returned."
  96. (if (null? rest)
  97. (let lp ((l list1)
  98. (rl '()))
  99. (if (null? l)
  100. (reverse! rl)
  101. (let ((res (proc (car l))))
  102. (if res
  103. (lp (cdr l) (cons res rl))
  104. (lp (cdr l) rl)))))
  105. (let lp ((l (cons list1 rest))
  106. (rl '()))
  107. (if (any1 null? l)
  108. (reverse! rl)
  109. (let ((res (apply proc (map car l))))
  110. (if res
  111. (lp (map cdr l) (cons res rl))
  112. (lp (map cdr l) rl)))))))