Idea for algorithm for renaming in an Clojure IDE

2012-04-13 Thread André Ferreira
I was thinking about how things like function or variable renaming are
complicated by lisps macros. That it's almost impossible to track the
scope of anything, since 2 symbols near each other might mean
completely different things after macro expansion.
So I came up with an algorithm that *might* work in the most common
case. Is there a flaw in the idea, or did I overlook any major aspect
of the language? Any idea of which IDE would be the best to try and
prototype it?

Here it is in pseudocode:

select symbol in source that you want to rename
parse the code
add tracking meta-data (file, line, position in line) into all symbols
of the tree
expand all macros
find selected symbol: it's either a definition in a def form or let*
or letfn form, or a variable being
used
if the symbol is a definition, find all places where it is used,
taking scope into account
   use metadata to find where the symbol was in the source code
   if it wasn't, it means a macro expanded it into place, so fail
   else rename it
if the symbol is a variable, find where it was defined, taking scope
into account
use metadata to rename it, if there is none, fail
find all symbols that refer to the definition, rename if there is
metadata, fail otherwise

-- 
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


Re: Regarding lexical scoping and usage of 'let' in a recursive function call

2010-11-12 Thread André Ferreira
Well, a more important matter, this example in the documentation of
atom is wrong!
The recursive calls will not be memoized if called like that. Running
this code clearly shows:

(defn memoize [f]
  (let [mem (atom {})]
(fn [ args]
  (if-let [e (find @mem args)]
(val e)
(let [ret (apply f args)]
  (swap! mem assoc args ret)
  ret)

(defn fib [n]
  (if (= n 1)
n
(+ (fib (dec n)) (fib (- n 2)

(time (fib 35))

user= Elapsed time: 1218.15834 msecs
(def fib (memoize fib))

(time (fib 35))

user= Elapsed time: 953.94816 msecs

I believe this is caused because defn creates a named fn:
user= (macroexpand '(defn fib [n]
(if (= n 1)
  n
  (+ (fib (dec n)) (fib (- n 2))

(def fib (.withMeta (clojure.core/fn fib ([n] (if (= n 1) n (+ (fib
(dec n)) (fib (- n 2)) (.meta (var fib

So the recursive call don't go through the global user/fib that has
been memoized, but by the local fib which hasn't.
So a correct way to write it would be:

(defn fib [n]
  (if (= n 1)
n
(+ (user/fib (dec n)) (user/fib (- n 2)

(def fib (memoize fib))

(time (fib 35))

user= Elapsed time: 0.814599 msecs

By fully qualifying the recursive call, it forces it to use the global
var, memoizing all the recursive calls.
This example should be corrected.

On Nov 12, 2:13 pm, Joseph Smith j...@uwcreations.com wrote:
 In this case 'memoize' returns a memoized version of the function 'f', which 
 closes over 'mem'. Each time 'memoize' is called a new atom is created, not 
 each time the function it returns is called.

 ---
 Joseph Smith
 j...@uwcreations.com

 On Nov 11, 2010, at 2:06 PM, Manoj wrote:







  I am a newbie to Clojure, so have some confusion around lexical
  scoping especially when let is used in a recursive function call. To
  be more precise, I am taking the example memoize() function used for
  explaining the concept of atom at clojure.org.

  Here is how it is explained:

  (defn memoize [f]
   (let [mem (atom {})]
     (fn [ args]
       (if-let [e (find @mem args)]
         (val e)
         (let [ret (apply f args)]
           (swap! mem assoc args ret)
           ret)

  (defn fib [n]
   (if (= n 1)
     n
     (+ (fib (dec n)) (fib (- n 2)

  (time (fib 35))
  user= Elapsed time: 941.445 msecs

  (def fib (memoize fib))

  (time (fib 35))

  user= Elapsed time: 0.044 msecs

  My question is when let is used in this context, wouldn't it create
  a fresh binding to a new atom{}? Any explanation would be highly
  appreciated.

  Thanks.

  --
  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 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


Re: Confused about =, native java arrays and seqs...

2010-03-24 Thread André Ferreira
Arrays are mutable, seqs immutable. Clojure ='s compares immutable
structures by value, and mutable structures by reference (for the
objects that it is aware of, for others it just prays that they have a
resoanable equals method). This behaviour is described in the very
interisting Henry Baker's egal Paper, and yields the cleanest equality
semantics that I know of.

On 23 mar, 14:24, Frank Siebenlist frank.siebenl...@gmail.com wrote:
 My REPL shows:
 ...
 user (= (bytes (.getBytes a))(bytes (.getBytes a)))
 false
 user (= (seq (bytes (.getBytes a))) (seq (bytes (.getBytes a
 true
 ...

 in other words, equality for java byte arrays is defined differently than 
 their seq'ed version.

 It seems that the native arrays are compared on their reference while the 
 seq'ed version on their value (as it should...).

 Sometimes the seq'ing seems implied, however, like in:

 ...
 user (first (bytes (.getBytes a)))
 97
 ...

 but for the = function it is not.

 This doesn't feel right and is confusing to say the least.

 Could anyone shed some light on this behaviour?

 Thanks, Frank.

-- 
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

To unsubscribe from this group, send email to 
clojure+unsubscribegooglegroups.com or reply to this email with the words 
REMOVE ME as the subject.


Re: bounded memoize

2010-03-08 Thread André Ferreira
On 8 mar, 23:22, Michał Marczyk michal.marc...@gmail.com wrote:
 I'd suggest a vector instead; they're countable in constant time and
 you can use, say, conj and rest for add to end of queue / eject from
 front of queue.

Conj adds to the end of a vector in constant time, but rest will not
return another vector, but a sequence. Converting that sequence into
another vector will take O(n). If you want queueing behaviour, you
should use a clojure.lang.PersistentQueue:
(- clojure.lang.PersistentQueue/EMPTY (conj 5) (conj 7) pop (conj 8)
peek)

-- 
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


Defn-memo doesn't work for recursive functions

2010-03-07 Thread André Ferreira
;Simple example
(defn fib1 [n]
  (if (or (= 0 n) (= 1 n))
1
(+ (fib1 (- n 1))
  (fib1 (- n 2)

(defn-memo fib2 [n]
  (if (or (= 0 n) (= 1 n))
1
(+ (fib2 (- n 1))
  (fib2 (- n 2)

;workaround for this problem
(declare aux-fib)
(defn-memo fib3 [n]
  (if (or (= 0 n) (= 1 n))
1
(+ (aux-fib (- n 1))
  (aux-fib (- n 2)
(def aux-fib fib3)

(time (fib1 35))
Elapsed time: 4729.9318 msecs
14930352
= (time (fib2 35))
Elapsed time: 4727.70348 msecs
14930352
= (time (fib3 35))
Elapsed time: 0.875 msecs
14930352


The recursive call inside fib2 is not memoized because of the way
Clojure expands defn, adding the function name to the generated fn.
So, how to rewrite defn-memo so that fib2 behaves like fib3? It would
be much easier to make defn stop adding the function name to the fn,
but that makes normal recursive functions a little slower, and would
change the behaviour if dynamic scoping was being used in a program.
The problem is that if you change defn-memo so that it doesn't use
defn, you lose all of defn goodness or have to reproduce all of defn's
work inside of defn-memo. Memoization of recursive functions is very
useful, with problems that are normally solved with dynamic program
becoming much simpler and functional when used. Any idea on how to
rewrite defn-memo so that it does the right thing?

-- 
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


Re: Interesting ICFP slides from Guy Steele -- Organizing Functional Code for Parallel Execution

2010-02-10 Thread André Ferreira
What he said is basically right, only instead of list it's called
vector. Not sure if vector branching is 64 or 32.

On 10 fev, 15:42, Paul  Mooser taron...@gmail.com wrote:
 I ran across this on reddit this morning, and thought people on the
 group might find it interesting:

 http://docs.google.com/viewer?url=http%3A%2F%2Fresearch.sun.com%2Fpro...

 It actually mentions clojure briefly at the end, although I'm not sure
 what it said was right (that lists were represented as trees in
 clojure). Nonetheless, the slide deck is pretty interesting.

-- 
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


Re: Clojure Scoping Rules

2009-11-23 Thread André Ferreira
Would it be possible to create an implementation of delay and lazy-seq
that didn't use fn to delay evaluation, or atleast captured dynamic
variables?

(delay (+ x 3))  reasonable semantics in current clojure (let [x x]
(delay (+ x 3)))
(delay (fn [y] (+ x y))) semantics should be the same it already is (x
should get it's value from the dynamic binding)
(delay [x (fn [y] (+ x y))]) semantics should be (let [G_N x] (delay
[G_N (fn [y] (+ x y))])), so all captured variables would need
renaming using gensyms.

delay would need it's body macroexpanded code to be able to correctly
capture variables. It would also try to capture local variables, but
that wouldn't change the semantics and would probably be optimized
away by the compiler.
I might have missed some important detail, since dynamic binding and
lazyness have such a peculiar semantics interaction, but it would
yield much more reasoanable execution, wouldn't it?

-- 
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


Re: Gensym collisions can be engineered.

2009-11-08 Thread André Ferreira

It's one thing to try to protect the programmer from accidentally
shooting himself on the foot, but I don't think it is as necessary for
a language to prevent him from doing it on purpose.

On 8 nov, 02:59, John Harrop jharrop...@gmail.com wrote:
 user= (def q 'G__723)
 #'user/q
 user= (def r (gensym))
 #'user/r
 user= q
 G__723
 user= r
 G__723
 user= (= q r)
 true

 It's possible to anticipate the next gensym name that will be generated and
 then engineer a collision, and therefore possibly variable capture
 unintended by the author of a macro.

 It looks like manually generating a name does not remove it from the pool
 of allowable future gensym names.

 This shouldn't tend to cause accidental problems in practice, since gensym
 names tend not to collide with the kinds of identifiers programmers
 ordinarily use. Nonetheless it can be partially fixed comparatively easily
 by adding to the runtime a WeakHashMap into which a reference to any symbol,
 however created, is placed and modifying the gensym-generator to, at the
 point where it currently returns a value, first check if the WeakHashMap
 contains it already and if so, generate the next one, and the next, as
 needed until it gets a not-in-use name. This requires gensym creation and
 normal symbol creation to occur in a global lock but symbol creation rarely
 occurs at runtime and even more rarely in any kind of hot-spot at runtime.
 The use of WeakHashMap would prevent the runtime clogging up with
 ungarbagecollectable symbols, so the memory overhead of adding this would be
 smallish, one machine pointer per in-use symbol or so, equivalent to if
 every symbol had a few more characters in its name.

 This would stop gensym from producing a name already in use. It wouldn't
 prevent a gensym being generated somewhere and *then* the identical name
 being put together someplace else and passed to the symbol function, though;
 a small loophole. Collisions between gensyms in preexisting code and an
 enclosing lexical scope in new code would become impossible, but collisions
 between gensyms in preexisting code and an enclosed lexical scope (e.g. a
 macro-invocation body, such as a loop body) would remain theoretically
 possible.

 That last loophole can't really be plugged without giving Clojure true
 gensyms (uninterned anywhere), which would bring with it its own
 architectural problems. If that change were made, the above REPL interaction
 would be possible up to the (= q r) evaluation, but that would return false
 despite the names looking the same, so the symbols wouldn't really collide
 even though a collision of their printed representations could still be
 engineered. One bothersome consequence though would be that the textual
 output of macroexpand-1 could no longer always be substituted for a macro
 call in source code without altering the run-time semantics of that code,
 even when the macro's expansion-generation does not have side effects.

 (To reproduce that REPL interaction for yourself, evaluate (gensym) at the
 REPL and note the number. Add seven and then evaluate (def q 'G__#) with #
 replaced with the sum. Then evaluate (def r (gensym)) and, if you like, skip
 straight to (= q r). If that doesn't work, the number it goes up by must
 have changed between Clojure 1.0 and whatever version you're using; evaluate
 (gensym), then (def q 'xyzzy), then (gensym) again and note the increment
 and use that instead of seven. Oh, and don't have any background threads
 running in that JVM instance that might do something autonomously that
 causes a gensym to be generated.)
--~--~-~--~~~---~--~~
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
-~--~~~~--~~--~--~---



Re: Proposal: New Reader Macro #s{ ... }

2009-10-12 Thread André Ferreira

Lua's solution to long strings is having multiple levels of
delimiters. [[ is the opening delimiter of level 0, and is closed
by ]] . [=[ is of level 1, closed by ]=] , etc.
No matter what string you are trying to represent, it can always be
literally represented that way.

On 12 out, 17:25, Greg g...@kinostudios.com wrote:
 Ah, I think I understand... but if you're saying that this should be  
 something that can be done on an individual basis I think that's a bad  
 idea, it would lead to confusing looking code and inconsistencies.

 There should be an officially sanctioned .. whatever it is this thing  
 is called. That way whenever you look at someone else's code and see  
 it, you know what it is, and people can update their code parser's/
 syntax highlighters appropriately.

 - Greg

 On Oct 12, 2009, at 2:59 PM, DanL wrote:



  On 12 Okt., 20:46, Greg g...@kinostudios.com wrote:

  Forgive me, but I'm unfamiliar with the readtable, are you just
  referring to where this syntax might be implemented? Or are you
  suggesting an alternative syntax?

  I'm suggesting that the readtable might be exposed to user changes as
  it is in CL, but only if a means of managing different readtables is
  provided, hence the link pointing to named-readtables, which allows
  just that (naming and merging readtables using an API resembling the
  package API). This would allow introduction of new reader macros by
  the user.

  As I said, there already was some discussion on that topic, but I just
  have played around with named-readtables since the new release and
  came to the conclusion, that something akin to them might be nice in
  clojure, too. Things like heredocs are not something that every user
  needs every day, so they would, IMHO, be a good candidate for a user
  readmacro.

  Regards,

  dhl
--~--~-~--~~~---~--~~
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
-~--~~~~--~~--~--~---



Re: Is apply slow or am I incorrectly benchmarking this?

2009-05-20 Thread André Ferreira

If efficiency is really an issue (if it's not just use apply), how
about using a macro for doing the dirty work of writing the direct
function application for you?

On 20 maio, 19:44, CuppoJava patrickli_2...@hotmail.com wrote:
 Thanks a lot for that really detailed analysis Stephen.
 I do find apply very convenient in a lot of cases, and am using it
 to save a line or two of code whenever I can. But after seeing this
 benchmark, I think I shall be more disciplined about my use of it.
 Especially in the case where the number of arguments of known, I can
 it's better to use the direction function application, even if it
 requires a little more typing.

 That seems to be a very useful tool. I'm gonna keep YourKit in mind in
 the future.

 Thanks again
   -Patrick
--~--~-~--~~~---~--~~
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
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
-~--~~~~--~~--~--~---



Amb operator

2009-04-09 Thread André Ferreira

So, I was wondering if anyone had implemented the amb operator in
Clojure, so I decided to give it a try. This is my first Clojure
program bigger then 5 lines, the code still needs ALOT of work, it is
ugly as hell atm, but I think it kind of works. (Yes, I know, it's
very easy to bug it, its just a sketch). Notice that unlike most
continuation based amb operators, the amount of backtracking this
implementation has to do depends on the order of the requires, not the
amb assignments.
If anyone wants to clear or improve the code, go ahead.
I also would like to know how to be able to write @baker instead of
the current (myderef baker), I tried using a proxy and implementing
IDeref, but then I couldn't acess the amb-struct private data. Since
Clojure doesn't have continuations I had to use a try catch block to
do the stack unwinding, and some redundant calculations might be done
because of it.

Here is the code:

(defstruct amb-struct :instance :orig :possible)

(def amb-stack nil)
(defn amb [choices]
  (struct-map amb-struct :instance false :orig choices  :possible
choices))

(defn myderef [a]
  (if (:instance @a)
(:value @a)
(do
  (set! amb-stack (cons a amb-stack))
  (let
  [oldpos (:possible @a)]
(var-set a (assoc @a
 :value (first oldpos)
 :instance true
 :possible (rest oldpos
  (:value @a

(defn amb-require [condition]
  (if condition
nil
(do
  (throw (.Exception nothing)

(defn bindnext []
  (if (empty? amb-stack)
'nomatchfound
(let [lastbind (first amb-stack)
  oldpos (:possible @lastbind)]
  (if (empty? oldpos)
(do
  (var-set lastbind (assoc @lastbind :instance false :possible (:orig
@lastbind)))
  (set! amb-stack (rest amb-stack))
  (recur))
(do
  (var-set lastbind (assoc @lastbind :value (first oldpos) :possible
(rest oldpos)))
  'recur)


(defmacro amb-let [declarations  body]
  `(with-local-vars
~declarations
  (binding [amb-stack nil]
(loop []
  (let [retvalue#
(try
 (do ~...@body)
 (catch Exception ~'except
   (bindnext)))]
(cond
  (= retvalue# 'recur) (recur)
  true retvalue#))

(defn distinct-seq? [s]
  (cond
(empty? (rest s)) true
(= (first s) (second s)) false
true (and (distinct-seq? (cons (first s) (rest (rest s
  (distinct-seq? (rest s)

(amb-let [baker (amb [1 2 3 4 5])
  cooper (amb [1 2 3 4 5])
  fletcher (amb [1 2 3 4 5])
  miller (amb [1 2 3 4 5])
  smith (amb [1 2 3 4 5])]
  (amb-require (distinct-seq? (map myderef (list baker cooper fletcher
miller smith
  (amb-require (not (= (myderef baker) 5)))
  (amb-require (not (= (myderef cooper) 1)))
  (amb-require (not (= (myderef fletcher) 1)))
  (amb-require (not (= (myderef fletcher) 5)))
  (amb-require ( (myderef miller) (myderef cooper)))
  (amb-require (not (= 1 (. java.lang.Math abs (- (myderef smith)
(myderef fletcher))
  (amb-require (not (= 1 (. java.lang.Math abs (- (myderef fletcher)
(myderef cooper))
  [['baker (myderef baker)]
   ['cooper (myderef cooper)]
   ['fletcher (myderef fletcher)]
   ['miller (myderef miller)]
   ['smith (myderef smith)]])

Running it returns [[baker 3] [cooper 2] [fletcher 4] [miller 5]
[smith 1]]

--~--~-~--~~~---~--~~
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
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
-~--~~~~--~~--~--~---



Re: doseq vs. map

2009-04-03 Thread André Ferreira

Laziness is the rule only on sequence operations.

On Apr 2, 11:34 pm, Sean francoisdev...@gmail.com wrote:
 Thanks for the response everyone!  I was able to get it working.  If I
 understand what everyone is saying, the following statement is true:

 In Clojure, laziness is the rule not the exception.

--~--~-~--~~~---~--~~
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
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
-~--~~~~--~~--~--~---