Re: Something like cond, but with test-fns

242 views
Skip to first unread message

Cedric Greevey

unread,
Apr 20, 2013, 12:47:27 PM4/20/13
to clo...@googlegroups.com
On Sat, Apr 20, 2013 at 5:15 AM, Ken Scambler <ken.sc...@gmail.com> wrote:
Hi there,
I'm getting started with Clojure, and found myself really missing Scala-style pattern matching.   Now I know about Matchure and core.match, but all I really needed was a cond using test predicates rather than boolean expressions, like this:

(condval value
  foo-pred? (foo-result)
  bar-pred? (bar-result)
  else? (default-result))

(Where 'else? is a predicate that ignores the argument and returns true)

Lisp being Lisp, I rolled my own and it works fine.

How different was what you came up with from this?

(def else? (constantly true))

(defmacro condval [vname & body]
  `(cond
     ~@(interleave (map (fn [p] `(~p ~vname)) (take-nth 2 body))
                   (take-nth 2 (rest body)))))

Just out of curiosity. :)

Cedric Greevey

unread,
Apr 20, 2013, 1:18:24 PM4/20/13
to clo...@googlegroups.com
Huh. Now that I think of it, the pattern of transforming every second item in a list is fairly often recurring, particularly (though not exclusively) in macro writing (mainly because of things like cond, bindings, and such that alternate two types of item, with dissimilar roles, in a sequential).

And that, in turn, suggests

(defn multimap [coll f & fs]
  (map #(%1 %2) (cycle (cons f fs)) coll))
and, of course,


(defmacro condval [vname & body]
  `(cond
     ~@(multimap body (fn [p] `(~p ~vname)) identity)))

(Incidentally, did you know that (take-nth 0 foo) will hang rather than throw an exception? In fact, it returns an infinite lazy seq of the first element of foo repeated forever, if foo isn't empty, but trying to print this result hangs the REPL. Weirder, (take-nth -1 foo) will do the same thing, rather than walk backwards off the near end of foo and throw an IndexOutOfBoundsException when, say, foo is a vector.

Ben Wolfson

unread,
Apr 20, 2013, 1:28:15 PM4/20/13
to clo...@googlegroups.com
On Sat, Apr 20, 2013 at 2:15 AM, Ken Scambler <ken.sc...@gmail.com> wrote:

Lisp being Lisp, I rolled my own and it works fine.   But I was wondering if there was an idiomatic way to do this in the standard library, without the repetition that cond necessitates when you are testing against a single value.

user=> (defn app-p [p v] (p v))
#'user/app-p
user=> (condp app-p 3
  #_=>    even? (println "even")
  #_=>    odd? (println "odd"))
odd
nil
user=>


--
Ben Wolfson
"Human kind has used its intelligence to vary the flavour of drinks, which may be sweet, aromatic, fermented or spirit-based. ... Family and social life also offer numerous other occasions to consume drinks for pleasure." [Larousse, "Drink" entry]

Ken Scambler

unread,
Apr 22, 2013, 10:29:28 AM4/22/13
to clo...@googlegroups.com


How different was what you came up with from this?

(def else? (constantly true))

(defmacro condval [vname & body]
  `(cond
     ~@(interleave (map (fn [p] `(~p ~vname)) (take-nth 2 body))
                   (take-nth 2 (rest body)))))

Just out of curiosity. :)

I just naively adapted the cond macro:

(defmacro condval
  [target & clauses]
    (when clauses
      `(if (~(first clauses) ~target)
            ~(if (next clauses)
                (second clauses)
                (error "condval requires an even number of forms"))
            (my-stuff.utils/condval ~target ~@(next (next clauses))))))


(defn else? [_] true)

Learned a lot from your version though, thanks!  I'm still yet to memorize all the useful combinators in the library.

 

Gary Verhaegen

unread,
Apr 27, 2013, 2:40:22 PM4/27/13
to clo...@googlegroups.com
On 22 April 2013 16:29, Ken Scambler <ken.sc...@gmail.com> wrote:
> Learned a lot from your version though, thanks! I'm still yet to memorize
> all the useful combinators in the library.

If, like me, you can't memorize long lists of vocabulary by just
reading them, I would suggest you to try 4clojure.org, which is a
really great way to get acquainted with the standard seq functions.

Stuart Sierra

unread,
Apr 28, 2013, 2:37:34 PM4/28/13
to clo...@googlegroups.com
You could do it with `condp`:

(condp #(%1 %2) value

  foo-pred? (foo-result)
  bar-pred? (bar-result)
  else? (default-result))

-S




On Saturday, April 20, 2013 5:15:14 AM UTC-4, Ken Scambler wrote:
Hi there,
I'm getting started with Clojure, and found myself really missing Scala-style pattern matching.   Now I know about Matchure and core.match, but all I really needed was a cond using test predicates rather than boolean expressions, like this:

(condval value
  foo-pred? (foo-result)
  bar-pred? (bar-result)
  else? (default-result))

(Where 'else? is a predicate that ignores the argument and returns true)

Lisp being Lisp, I rolled my own and it works fine.   But I was wondering if there was an idiomatic way to do this in the standard library, without the repetition that cond necessitates when you are testing against a single value.

Cheers,
Ken

Ken Scambler

unread,
Apr 30, 2013, 8:48:03 PM4/30/13
to clo...@googlegroups.com
That's the one I want.  Thanks!


--
--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clo...@googlegroups.com
Note that posts from new members are moderated - please be patient with your first post.
To unsubscribe from this group, send email to
clojure+u...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
---
You received this message because you are subscribed to a topic in the Google Groups "Clojure" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/clojure/ZLu3E-tr_Y4/unsubscribe?hl=en.
To unsubscribe from this group and all its topics, send an email to clojure+u...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Reply all
Reply to author
Forward
0 new messages