You could use pattern matching with core.match On 05/09/2013 6:57 AM, "Bruno Kim Medeiros Cesar" <brunokim...@gmail.com> wrote:
> I'm writing (another) basic graph library, and would like to treat inputs > depending on the type of the graph. A graph can be > > - Directed, in which case edges are vectors. Otherwise, edges are sets; > - Looped, allowing edges from a node to itself; > - Pseudo (or multi), allowing multiples edges between the same > endpoints; and > - Hyper, allowing edges with more than two vertices. > > To illustrate better these characteristics you can think of a scientific > publication network as a directed, looped, pseudo-hypergraph. Vertices are > authors, and edges are articles containing multiple researchers (hyper) who > can publish alone (looped). There are multiple articles between the same > researchers (pseudo) and in some contexts author order matters (directed). > > Now, I've created a flowchart <http://imgur.com/IdgsGFG> to decide if an > edge should be conjed in a graph :edges entry, that leads to the following > straightforward function: > (defn add-edge > ([graph v1 v2 & vs] (add-edge graph (concat [v1 v2] vs))) > ([graph edge] > (if (and (multi? graph) (not= 2 (count edge))) > graph > (if (and (looped? graph) (not (distinct? edge))) > graph > (let [e (if (directed? edge) (vec edge) (set edge))] > (update-in graph [:edges] conj e)))))) > > That looks ugly and a pattern that could propagate in a codebase. So I > tried to factor out multimethods from it, and ended with the following: > > (defmulti ^:private add-edge0 (fn [g e] (hyper? g))) > (defmulti ^:private add-edge1 (fn [g e] (looped? g))) > (defmulti ^:private add-edge2 (fn [g e] (directed? g))) > (defn ^:private add-edge3 [g e] > (update-in g [:edges] conj e)) > > (defmethod add-edge0 :hyper [g e] (add-edge1 g e)) > (defmethod add-edge0 :default [g e] (if (= 2 (count e)) > (add-edge1 g e) > g)) > (defmethod add-edge1 :looped [g e] (add-edge2 g e)) > (defmethod add-edge1 :default [g e] (if (distinct? e) > (add-edge2 g e) > g)) > (defmethod add-edge2 :directed [g e] (add-edge3 g (vec e))) > (defmethod add-edge2 :default [g e] (add-edge3 g (set e))) > > (defn add-edge > ([g v1 v2 & vs] (add-edge g (concat [v1 v2] vs))) > ([g edge] (add-edge0 g edge))) > > That doesn't look much better, as the amount of boilerplate increased, but > at least the concerns for each type are separated. > > Do you have any suggestions on how to improve this design? Thanks for any > consideration! > > Bruno Kim Medeiros Cesar > Engenheiro de Computação > Pesquisador em Redes Complexas > www.brunokim.com.br > > -- > -- > You received this message because you are subscribed to the Google > Groups "Clojure" group. > To post to this group, send email to clojure@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+unsubscr...@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 the Google Groups > "Clojure" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to clojure+unsubscr...@googlegroups.com. > For more options, visit https://groups.google.com/groups/opt_out. > -- -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@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+unsubscr...@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 the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/groups/opt_out.