Advertisement
Guest User

Common lisp list comprehension (just for lulz) №2

a guest
Dec 25th, 2014
184
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 4.38 KB | None | 0 0
  1. (require 'asdf)
  2. (asdf:load-system :split-sequence)
  3.  
  4. (defpackage list-comprehension (:use :cl :split-sequence))
  5. (in-package :list-comprehension)
  6.  
  7. (defun subseq-position (subseq sequence &key (test #'eql))
  8. (labels ((subseq-position% (subseq)
  9. (if (> (length subseq) 0)
  10. (let ((first-elem-pos (position (elt subseq 0) sequence :test test)))
  11. (if first-elem-pos
  12. (multiple-value-bind (pos found)
  13. (subseq-position% (subseq subseq 1))
  14. (declare (ignore pos))
  15. (if found (values first-elem-pos t)))))
  16. (values nil t))))
  17. (values (subseq-position% subseq))))
  18.  
  19. (defun reader-macro-[ (stream char)
  20. (declare (ignore char))
  21. (let* ((expr (coerce (loop for char = (read-char stream)
  22. while (char/= char #\]) collect char)
  23. 'string))
  24. (clauses (split-sequence #\, expr))
  25. (gen-name (gensym))
  26. bindings aux-bindings conditions side-effects)
  27. ;; First clause is a 'collect' clause
  28. (destructuring-bind (collect-form . rest) clauses
  29. (when rest
  30. (loop for clause in rest do
  31. (cond
  32. ;; Binding
  33. ((subseq-position "<-" clause)
  34. (let* ((position (subseq-position "<-" clause))
  35. (var (subseq clause 0 position))
  36. (value (subseq clause (+ 2 position))))
  37. (push (list (gensym)
  38. (read-from-string var)
  39. (read-from-string value)) bindings)))
  40. ;; Side effects
  41. ((find #\^ clause)
  42. (push (read-from-string (remove #\^ clause)) side-effects))
  43. ;; Aux bindings
  44. ((subseq-position "==" clause)
  45. (let* ((position (subseq-position "==" clause))
  46. (var (subseq clause 0 position))
  47. (value (subseq clause (+ 2 position))))
  48. (push (cons (read-from-string var)
  49. (read-from-string value))
  50. aux-bindings)))
  51. ;; Condition
  52. (t
  53. (push (read-from-string clause) conditions))))
  54.  
  55. `(let
  56. ;; Set environment
  57. ,(loop for binding in bindings collect
  58. (destructuring-bind (sym var value) binding
  59. (declare (ignore var))
  60. `(,sym ,value)))
  61.  
  62. (labels ((,gen-name ()
  63. (when (or ,@(loop for binding in bindings
  64. for sym = (first binding) collect sym))
  65. ;; Set bindings
  66. (let*
  67. (,@(loop for binding in bindings collect
  68. (destructuring-bind (sym var value) binding
  69. (declare (ignore value))
  70. `(,var (first ,sym))))
  71. ,@(loop for binding in aux-bindings collect
  72. (destructuring-bind (var . value) binding
  73. `(,var ,value))))
  74.  
  75. ;; Modify lists
  76. ,@(loop for binding in bindings collect
  77. `(setq ,(car binding) (cdr ,(car binding))))
  78.  
  79. (if ,(if conditions `(and ,@conditions) t)
  80. (progn
  81. ;; Run side effects first
  82. ,@side-effects
  83. ,(read-from-string collect-form))
  84. (,gen-name))))))
  85. #',gen-name))))))
  86.  
  87. (set-macro-character #\[ #'reader-macro-[)
  88. (set-macro-character #\] (get-macro-character #\)))
  89.  
  90. (defun all (gen)
  91. (loop for val = (funcall gen)
  92. while val collect val))
  93.  
  94. (defmacro test (bool)
  95. `(if (not ,bool)
  96. (format *error-output* "~a is not t~%" ',bool)))
  97.  
  98. (defun run-tests ()
  99. (test (equal (all [(* x y), x <- '(0 1 1), y <- '(2 1 4)]) '(0 1 4)))
  100. (test (equal (all [x, x <- (loop for i below 6 collect i), (oddp x)]) '(1 3 5)))
  101. (test (equal (all [y, x <- (loop for i below 3 collect i), y == (* 2 x)]) '(0 2 4)))
  102. (test
  103. (string= "hihihi"
  104. (with-output-to-string (out)
  105. (all
  106. [x, x <- (loop repeat 3 collect t), ^ (format out "hi")])))))
  107. (run-tests)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement