Skip to content
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

Sequential threading/anaphoric cond-like macro idea #234

Open
alphapapa opened this issue Sep 6, 2017 · 7 comments
Open

Sequential threading/anaphoric cond-like macro idea #234

alphapapa opened this issue Sep 6, 2017 · 7 comments
Labels
enhancement Suggestion to improve or extend existing behavior

Comments

@alphapapa
Copy link

alphapapa commented Sep 6, 2017

Note: It's no longer proposed that these macros be named -cond->> and --cond->. See this comment.

Hey, it's me again, another idea. :)

(defmacro -cond->> (test &rest forms)
  (declare (indent defun))
  `(cond ,@(cl-loop for form in forms
                    for this-test = (pcase (car form)
                                      ('t t)
                                      (_ (append test (list (car form)))))
                    collect (list this-test
                                  (cadr form)))))

Used like:

(-cond->> (<= difference)
  (14400 ;; Within past 4 hours
   100)
  (86400 ;; Within last day
   80)
  (259200 ;; Within last 3 days
   60)
  (604800 ;; Within last week
   40)
  (2419200 ;; Within last 4 weeks
   20)
  (7776000 ;; Within last 90 days
   10)
  (t ;; More than 90 days
   0))

Which expands to:

(cond ((<= difference 14400)
       100)
      ((<= difference 86400)
       80)
      ((<= difference 259200)
       60)
      ((<= difference 604800)
       40)
      ((<= difference 2419200)
       20)
      ((<= difference 7776000)
       10)
      (t 0))

Saves a bit of repetition. Could also have a -cond-> form that uses each cond test as the second argument in the test form rather than the last, like the difference between ->> and ->.

@alphapapa
Copy link
Author

Here's another example where this would be useful: https://github.com/zk-phi/sky-color-clock/blob/master/sky-color-clock.el#L263:

(defun sky-color-clock--emoji-moonphase (time)
  (let* ((time-in-days (/ (float-time time) 60 60 24))
         (phase (mod (- time-in-days sky-color-clock--newmoon) sky-color-clock--moonphase-cycle)))
    (cond ((<= phase  1.84) "🌑")
          ((<= phase  5.53) "🌒")
          ((<= phase  9.22) "🌓")
          ((<= phase 12.91) "🌔")
          ((<= phase 16.61) "🌕")
          ((<= phase 20.30) "🌖")
          ((<= phase 23.99) "🌗")
          ((<= phase 27.68) "🌘")
          (t                "🌑"))))

Which could be:

(defun sky-color-clock--emoji-moonphase (time)
  (let* ((time-in-days (/ (float-time time) 60 60 24))
         (phase (mod (- time-in-days sky-color-clock--newmoon) sky-color-clock--moonphase-cycle)))
    (-cond->> (<= phase)
      (1.84 "🌑")
      (5.53 "🌒")
      (9.22 "🌓")
      (12.91 "🌔")
      (16.61 "🌕")
      (20.30 "🌖")
      (23.99 "🌗")
      (27.68 "🌘")
      (t "🌑"))))

@alphapapa
Copy link
Author

By the way, an anaphoric version:

(defmacro --cond-> (test &rest forms)
  (declare (indent defun))
  `(cond ,@(cl-loop for (it result) in forms
                    when (eq it t)
                    do (setq test t)
                    collect (list `(let ((it ,it))
                                     ,test)
                                  result))))

e.g. FizzBuzz:

(cl-loop for n from 1 to 100
         collect (--cond-> (= 0 (% n it))
                   (15 (list n "FizzBuzz"))
                   (3 (list n "Fizz"))
                   (5 (list n "Buzz"))
                   (t n)))
;; => (1 2 (3 "Fizz") 4 (5 "Buzz") (6 "Fizz") 7 8 (9 "Fizz") (10 "Buzz") 11 (12 "Fizz") 13 14 (15 "FizzBuzz") ...)

@Fuco1 Fuco1 added the enhancement Suggestion to improve or extend existing behavior label Jul 26, 2018
@oskarkv
Copy link

oskarkv commented Mar 25, 2020

@alphapapa That's not how Clojure's cond-> and cond->> work, and doing something else will probably be confusing for most people. In Clojure, cond->> takes something and test form pairs, like (cond->> something test1 form1 test2 form2 ...) and it puts something last in form1 if test1 is true, then that in form2 if test2 is true, etc.

What you have described is more akind to Clojure's condp.

Clojure's cond->> https://clojuredocs.org/clojure.core/cond-%3E%3E
Clojure's condp https://clojuredocs.org/clojure.core/condp

@basil-conto
Copy link
Collaborator

Does #349 satisfy this feature request?

@alphapapa
Copy link
Author

@basil-conto Not exactly; the examples I showed don't work on that PR's code. However, @oskarkv's comment may explain why. Maybe the macro I've shown here should be named differently so -cond->> could behave as Clojure's does.

Of course, naming things is hard, but I'll change the title of this issue to...something else...

@alphapapa alphapapa changed the title -cond->> macro? Sequential threading/anaphoric cond-like macro idea Dec 18, 2020
@basil-conto
Copy link
Collaborator

basil-conto commented Dec 18, 2020

Of course, naming things is hard, but I'll change the title of this issue to...something else...

Imagine the difficulty for someone reading Elisp code with all these many similar but subtly different "magic" macros. ;)

@alphapapa
Copy link
Author

Imagine the difficulty for someone reading Elisp code with all these many similar but subtly different "magic" macros. ;)

Yes, that's probably why not many of them have been implemented in a package. ;)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement Suggestion to improve or extend existing behavior
Projects
None yet
Development

No branches or pull requests

4 participants