How can I avoid reimplementing a function?

62 views
Skip to first unread message

Soham

unread,
Nov 12, 2012, 10:40:45 PM11/12/12
to 4clo...@googlegroups.com
So for problem 88, this is how I coded my solution

(fn [x y] 
  (into #{} (concat 
    ((fn foo [a b]
      (cond 
        (empty? a) a
        (not (contains? b (first a))) 
           (concat (list (first a)) (foo (rest a) b))
        :else (foo (rest a) b))
     ) x y)
    ((fn foo [a b]
      (cond 
        (empty? a) a
        (not (contains? b (first a))) 
           (concat (list (first a)) (foo (rest a) b))
        :else (foo (rest a) b))) y x)
    )
))

As you can see, I had to redefine the function foo twice, that is duplication of code. Is there any way that I can define the function once and then access it?

I tried using def in 4clojure and it said I was not allowed. Had similar issue declaring it with defn.

I tried defining the function foo outside of my anonymous main function like this.

(fn foo [a b]
      (cond 
        (empty? a) a
        (not (contains? b (first a))) 
           (concat (list (first a)) (foo (rest a) b))
        :else (foo (rest a) b))
     )
(fn [x y] 
  (into #{} (concat 
    (foo x y)
    (foo y x)
    )
))

And using foo inside anonymous function like following.

(fn [x y] 
  ((into #{} (concat 
    (foo x y)
    (foo y x)
    ))
    (fn foo [a b]
      (cond 
        (empty? a) a
        (not (contains? b (first a))) 
           (concat (list (first a)) (foo (rest a) b))
        :else (foo (rest a) b))
     )
))

But each time I get the message, that foo cannot be accessed. What is it, that I am messing up in scoping? 

Any help would be appreciated.

Thanks,
Soham

ctzsm

unread,
Nov 13, 2012, 3:16:52 AM11/13/12
to 4clo...@googlegroups.com
Hi,

You can try "letfn", and you know where to find the detail about it.

Yours.

Alan Malloy

unread,
Nov 13, 2012, 3:41:12 AM11/13/12
to 4clo...@googlegroups.com
Since a function is just a value, you can (let [f (fn ...)] ...) just like anything else. But often it's possible to restructure your problem so that you don't need to reuse a value. For example, without trying to figure out what your code does, I rewrote it to an equivalent form that I think is easier to read, and also avoids the need to let the function foo (although you still can, if you find it more readable).

(fn [x y]
  (set (mapcat (fn foo [a b]
                 (cond (empty? a) a,
                       (contains? b (first a)) (foo (rest a) b),
                       :else (cons (first a)
                                   (foo (rest a) b))))
               [x y], [y x])))

One thing to be careful of while reading the above is that it looks like foo is being called with args from the first vector (ie, x y) and then with args from the second vector (ie, y x). But actually it's getting called with the first item from each vector (also x y), and then the second item from each vector (also y x). So make sure you get what's going on there or my example may give you some misleading ideas to trick you later on.

Or, a version using (for), which is a pretty powerful macro for doing all sorts of stuff with lists. I think this one is harder to read than my first, but still nice enough.

(fn [x y]
  (set (for [[a b] [[x y], [y x]]
             item ((fn foo [a b]
                     (cond (empty? a) a,
                           (contains? b (first a)) (foo (rest a) b),
                           :else (cons (first a)
                                       (foo (rest a) b))))
                   a b)]
         item)))
Reply all
Reply to author
Forward
0 new messages