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.

Reply via email to