Re: Improving a nested if, or How to use multimethods the right way.

2013-09-05 Thread Alex Baranosky
I'd just use a cond to flatten a nested if. That's usually all you need,
imo.


On Thu, Sep 5, 2013 at 1:07 PM, Bruno Kim Medeiros Cesar 
brunokim...@gmail.com wrote:

 Thanks for your suggestion, didn't know about that! One of the things that
 made someone say that Clojure looks like a language from the near future.
 However, I'm having a hard time using it with its full power. Could you
 recommend any other resource, besides the overview page on github, to learn
 pattern matching? Maybe a project that uses them?

 For the record, my code uses a simple truth table now:


 (defn add-edge
   ([g v1 v2  vs] (add-edge g (concat [v1 v2] vs)))
   ([g edge]
(let [two? (= 2 (count edge))
  dist? (apply distinct? edge)
  e (match [(hyper? g) (looped? g)] ; e will be nil if edge is
 invalid for this graph
  [false false] (when (and two? dist?) edge)
  [false true ] (when two?  edge)
  [true  false] (when dist? edge)
  [true  true ] edge]
  (if e
(update-in g [:edges] conj (if (directed? g) (vec e) (set e)))
g

 On Wednesday, September 4, 2013 7:07:06 PM UTC-3, Leonardo Borges wrote:

 You could use pattern matching with core.match
 On 05/09/2013 6:57 AM, Bruno Kim Medeiros Cesar bruno...@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 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=enhttp://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+u...@**googlegroups.com.

 For more options, visit 
 https://groups.google.com/**groups/opt_outhttps://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 

Re: Improving a nested if, or How to use multimethods the right way.

2013-09-05 Thread Alex Baranosky
;; Better yet...

(if (or (and (multi? graph) (not= 2 (count edge)))
(and (looped? graph) (not (distinct? edge
graph
(let [e (if (directed? edge) (vec edge) (set edge))]
  (update-in graph [:edges] conj e


On Thu, Sep 5, 2013 at 2:22 PM, Alex Baranosky 
alexander.barano...@gmail.com wrote:

 I'd just use a cond to flatten a nested if. That's usually all you need,
 imo.


 On Thu, Sep 5, 2013 at 1:07 PM, Bruno Kim Medeiros Cesar 
 brunokim...@gmail.com wrote:

 Thanks for your suggestion, didn't know about that! One of the things
 that made someone say that Clojure looks like a language from the near
 future. However, I'm having a hard time using it with its full power.
 Could you recommend any other resource, besides the overview page on
 github, to learn pattern matching? Maybe a project that uses them?

 For the record, my code uses a simple truth table now:


 (defn add-edge
   ([g v1 v2  vs] (add-edge g (concat [v1 v2] vs)))
([g edge]
(let [two? (= 2 (count edge))
  dist? (apply distinct? edge)
  e (match [(hyper? g) (looped? g)] ; e will be nil if edge is
 invalid for this graph
  [false false] (when (and two? dist?) edge)
  [false true ] (when two?  edge)
  [true  false] (when dist? edge)
  [true  true ] edge]
  (if e
(update-in g [:edges] conj (if (directed? g) (vec e) (set e)))
g

 On Wednesday, September 4, 2013 7:07:06 PM UTC-3, Leonardo Borges wrote:

 You could use pattern matching with core.match
 On 05/09/2013 6:57 AM, Bruno Kim Medeiros Cesar bruno...@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 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=enhttp://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+u...@**googlegroups.com.

 For more options, visit 
 

Re: Improving a nested if, or How to use multimethods the right way.

2013-09-05 Thread Bruno Kim Medeiros Cesar
Thanks for your suggestion, didn't know about that! One of the things that 
made someone say that Clojure looks like a language from the near future. 
However, I'm having a hard time using it with its full power. Could you 
recommend any other resource, besides the overview page on github, to learn 
pattern matching? Maybe a project that uses them?

For the record, my code uses a simple truth table now:

(defn add-edge
  ([g v1 v2  vs] (add-edge g (concat [v1 v2] vs)))
  ([g edge]
   (let [two? (= 2 (count edge))
 dist? (apply distinct? edge)
 e (match [(hyper? g) (looped? g)] ; e will be nil if edge is 
invalid for this graph
 [false false] (when (and two? dist?) edge)
 [false true ] (when two?  edge)
 [true  false] (when dist? edge)
 [true  true ] edge]
 (if e
   (update-in g [:edges] conj (if (directed? g) (vec e) (set e)))
   g

On Wednesday, September 4, 2013 7:07:06 PM UTC-3, Leonardo Borges wrote:

 You could use pattern matching with core.match 
 On 05/09/2013 6:57 AM, Bruno Kim Medeiros Cesar 
 bruno...@gmail.comjavascript: 
 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 clo...@googlegroups.comjavascript:
 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 javascript:
 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+u...@googlegroups.com javascript:.
 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 

Re: Improving a nested if, or How to use multimethods the right way.

2013-09-05 Thread Bruno Kim Medeiros Cesar
Thanks, Alex, I was going down an over-engineering rabbit hole. Your 
solution just lacks a not before multi? and looped?.

On Thursday, September 5, 2013 6:24:13 PM UTC-3, Alex Baranosky wrote:

 ;; Better yet...

 (if (or (and (multi? graph) (not= 2 (count edge))) 
 (and (looped? graph) (not (distinct? edge
 graph
 (let [e (if (directed? edge) (vec edge) (set edge))]
   (update-in graph [:edges] conj e


 On Thu, Sep 5, 2013 at 2:22 PM, Alex Baranosky 
 alexander...@gmail.comjavascript:
  wrote:

 I'd just use a cond to flatten a nested if. That's usually all you need, 
 imo.


 On Thu, Sep 5, 2013 at 1:07 PM, Bruno Kim Medeiros Cesar 
 bruno...@gmail.com javascript: wrote:

 Thanks for your suggestion, didn't know about that! One of the things 
 that made someone say that Clojure looks like a language from the near 
 future. However, I'm having a hard time using it with its full power. 
 Could you recommend any other resource, besides the overview page on 
 github, to learn pattern matching? Maybe a project that uses them?

 For the record, my code uses a simple truth table now:


 (defn add-edge
   ([g v1 v2  vs] (add-edge g (concat [v1 v2] vs)))
([g edge]
(let [two? (= 2 (count edge))
  dist? (apply distinct? edge)
  e (match [(hyper? g) (looped? g)] ; e will be nil if edge is 
 invalid for this graph
  [false false] (when (and two? dist?) edge)
  [false true ] (when two?  edge)
  [true  false] (when dist? edge)
  [true  true ] edge]
  (if e
(update-in g [:edges] conj (if (directed? g) (vec e) (set e)))
g

 On Wednesday, September 4, 2013 7:07:06 PM UTC-3, Leonardo Borges wrote:

 You could use pattern matching with core.match 
 On 05/09/2013 6:57 AM, Bruno Kim Medeiros Cesar bruno...@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 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
 

Improving a nested if, or How to use multimethods the right way.

2013-09-04 Thread Bruno Kim Medeiros Cesar
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.


Re: Improving a nested if, or How to use multimethods the right way.

2013-09-04 Thread Leonardo Borges
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.