Re: bugs in with-local-vars and lexically-nested-function access to outer function parameters

2010-08-04 Thread Dale
 This statement is ironic, considering the definition of a functional
 closure, after which Clojure is presumably named.

 You're missing the point.  A defn inside another defn doesn't do what you
 think it does.  defn always creates a global variable, even when it looks
 like it should create a local.  You can create closures, but you should use
 letfn instead.

Got it, thanks -- a beginner's path through the intro web pages does
not lead one through letfn.

That fact is likely to throw people with background in Scheme more
than it is newbies to LISP-like languages, because the Schemers are
much more likely to be used to using a lexically scoped LISP, and
Clojure's constructs are a mix of lexical and dynamic scoping.


 Well if you can't duplicate the bug in a simpler context, it seems more
 likely that the bug is in the logic of your code, or your understanding of
 these constructs, doesn't it?

The invocation of with-local-vars or binding trashes the Clojure
environment when the invocation completes. Possibly it may be just an
application bug. It is also very possibly be that an unusual
combination of legitimately-used mechanisms have brought a bug to the
surface that does not come to the surface when these mechanisms are
used in isolation.

 Your example is long enough I only had time to glance briefly at it.  Based
 on what I could glean from that quick look, I think you may have a
 misunderstanding about how with-local-vars works. vars are thread-specific,
 and they have a lifetime that is delimted by dynamic scoping rather than
 lexical scoping.  Using vars in conjunction with futures seems like a recipe
 for disaster.

The vars collect results of invoking future. If these vars are never
dereferenced, presumably the references would be garbage collected,
regardless of the state of the threads spawned by those invocations.
These results are in fact dereferenced via calls to deref; these deref
calls do not return until the threads have terminated.

I have walked through all of this in Eclipse. The algorithm inside
with-local-vars or binding works as expected. The futures complete
their tasks and deref accomplishes synchronization before the with-
local-vars exits. When it exits, all currently active function
parameters shown by Eclipse revert to values of nill, even though the
function binding those parameters has not completed.

-- 
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: bugs in with-local-vars and lexically-nested-function access to outer function parameters

2010-08-03 Thread Moritz Ulrich
Defining function (with defn) inside another function isn't very
beautiful (def* outside of the top-level is generally disregarded). It
looks like you use thhelp only inside the thsolve-function. Use either
letfn or (let [thhelp (fn )] ...) here.

On Tue, Aug 3, 2010 at 5:07 AM, Mark Engelberg mark.engelb...@gmail.com wrote:
 Can you distill this down to the smallest possible example that demonstrates
 the error?

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



-- 
Moritz Ulrich
Programmer, Student, Almost normal Guy

http://www.google.com/profiles/ulrich.moritz

-- 
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: bugs in with-local-vars and lexically-nested-function access to outer function parameters

2010-08-03 Thread Dale
On Aug 2, 11:07 pm, Mark Engelberg mark.engelb...@gmail.com wrote:
 Can you distill this down to the smallest possible example that demonstrates
 the error?

Nope. Just spent some time trying to duplicate the nested function bug
in a simpler context.

A pointer to the place where I should deposit code that manifests a
run-time bug in Clojure would be the thing here. Code that reliably
exposes underlying bugs is like money in the bank.

-- 
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: bugs in with-local-vars and lexically-nested-function access to outer function parameters

2010-08-03 Thread Dale
On Aug 3, 11:26 am, Moritz Ulrich ulrich.mor...@googlemail.com
wrote:
 Defining function (with defn) inside another function isn't very
 beautiful (def* outside of the top-level is generally disregarded). It
 looks like you use thhelp only inside the thsolve-function. Use either
 letfn or (let [thhelp (fn )] ...) here.

This statement is ironic, considering the definition of a functional
closure, after which Clojure is presumably named.

From http://en.wikipedia.org/wiki/Closure_%28computer_science%29

In some languages, a closure may occur when a function is defined
within another function, and the inner function refers to local
variables of the outer function. At runtime, when the outer function
executes, a closure is formed, consisting of the inner function’s code
and references to any variables of the outer function required by the
closure; such variables are called the upvalues of the closure.

I haven't had an application for returning closures as first class
objects (yet), but presumably, if Clojure supports first-class
functions (see http://clojure.org/functional_programming) and allows
nested function definitions with lexical scope, then it supports
closures.

-- 
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: bugs in with-local-vars and lexically-nested-function access to outer function parameters

2010-08-03 Thread Mark Engelberg
On Tue, Aug 3, 2010 at 1:06 PM, Dale dpar...@ptd.net wrote:

 This statement is ironic, considering the definition of a functional
 closure, after which Clojure is presumably named.


You're missing the point.  A defn inside another defn doesn't do what you
think it does.  defn always creates a global variable, even when it looks
like it should create a local.  You can create closures, but you should use
letfn instead.

-- 
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: bugs in with-local-vars and lexically-nested-function access to outer function parameters

2010-08-03 Thread Mark Engelberg
On Tue, Aug 3, 2010 at 1:00 PM, Dale dpar...@ptd.net wrote:

 On Aug 2, 11:07 pm, Mark Engelberg mark.engelb...@gmail.com wrote:
  Can you distill this down to the smallest possible example that
 demonstrates
  the error?

 Nope. Just spent some time trying to duplicate the nested function bug
 in a simpler context.


Well if you can't duplicate the bug in a simpler context, it seems more
likely that the bug is in the logic of your code, or your understanding of
these constructs, doesn't it?

Your example is long enough I only had time to glance briefly at it.  Based
on what I could glean from that quick look, I think you may have a
misunderstanding about how with-local-vars works. vars are thread-specific,
and they have a lifetime that is delimted by dynamic scoping rather than
lexical scoping.  Using vars in conjunction with futures seems like a recipe
for disaster.  A null pointer exception would be not at all surprising to me
in this context, because the var goes away when the block of code that
created it exits.

I generally advise people to stay away from vars unless they know exactly
what they are doing.  Vars have all sorts of unintuitive interactions with
laziness and multithreading.

Try refactoring your algorithm in a way that doesn't need mutable locals.
If you absolutely do need a mutable local, just use an atom.

-- 
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: bugs in with-local-vars and lexically-nested-function access to outer function parameters

2010-08-03 Thread Mark Engelberg
Similarly, don't use def inside of a defn.  Use let.

On Tue, Aug 3, 2010 at 9:10 PM, Mark Engelberg mark.engelb...@gmail.comwrote:

 On Tue, Aug 3, 2010 at 1:06 PM, Dale dpar...@ptd.net wrote:

 This statement is ironic, considering the definition of a functional
 closure, after which Clojure is presumably named.


 You're missing the point.  A defn inside another defn doesn't do what you
 think it does.  defn always creates a global variable, even when it looks
 like it should create a local.  You can create closures, but you should use
 letfn instead.


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

bugs in with-local-vars and lexically-nested-function access to outer function parameters

2010-08-02 Thread Dale
In the program below, if I use the commented-out version of thsolve
(program is the N queens puzzle), the with-local-vars construct causes
a NullPointerException when its block exits, after appearingt o work
correctly. The same thing happens if I use binding instead.

The non-commented version of thsolve that uses a nested recursive
helper function thhelp does not work if thsolve does not explicitly
pass parameter thdepth to thhelp as a parameter. If I try to use
lexical nesting to let thhelp get the value of thdepth without making
thdepth a parameter of thhelp, then thhelp gets incorrect values at
run time. There is no error indicator, but the values are wrong.

These are in 1.1, and the first problem is in the current beta of 1.2.
Not sure where I should post this.

Dale

; Clojure solution to nqueens benchmark.
; D. Parson, Summer 2010.
; See threadlim_nqueens.java for more details.


(defstruct boardstate
  ; :xcol_occupied is (0 .. n-1), set to 1 for true when column
occupied
  ; :yrow_occupied is (0 .. n-1), set to true when row occupied.
  ;   value is stored as either 0 for false or the value x+1 for the y
  ;   value at the array index, so that the print method can extract
  ;   x,y pairs from yrow_occupied without storing yet another 2D
array,
  ;   which slows down both machines, especially Harry.
  ; :diag_occupied is (X+Y) is (0..2n-2) for / diagonal occupation
  ; :rdia_occupied is (X-Y+(n-1)) is (0..2n-2) for \ diagonal
occupation
  :nqueens :xcol_occupied :yrow_occupied :diag_occupied :rdia_occupied
)

; Construct an empty boardstate -- 0 in all vectors
(defn newboardstate [nqueens]
  (let [
diagsize (- (* 2 nqueens) 1)
line0 (for [i (range 0 nqueens)] 0)
diag0 (for [i (range 0 diagsize)] 0)
linev (vec line0)
diagv (vec diag0)
]
(struct-map boardstate
  :nqueens nqueens
  :xcol_occupied linev
  :yrow_occupied linev
  :diag_occupied diagv
  :rdia_occupied diagv
)
  )
)

; nextboardstate takes a previous board state and insert value
; state at location x,y, returning the new board
(defn nextboardstate [oldboard x y state]
  (let [
newxcol (assoc (get oldboard :xcol_occupied) x state)
newyrow (assoc (get oldboard :yrow_occupied) y state)
newdiag (assoc (get oldboard :diag_occupied) (+ x y) state)
newrdia (assoc (get oldboard :rdia_occupied)
(+ (- x y) (- (get oldboard :nqueens) 1)) state)
]
(struct-map boardstate
  :nqueens (get oldboard :nqueens)
  :xcol_occupied newxcol
  :yrow_occupied newyrow
  :diag_occupied newdiag
  :rdia_occupied newrdia
)
  )
)

; Check whether it is safe to place a queen at location x, y
; We can skip the [x] column check because solve uses only 1
; location at a time in a given column.
(defn issafe [board x y]
  (and
(== (nth (get board :yrow_occupied) y) 0)
(== (nth (get board :diag_occupied) (+ x y)) 0)
(== (nth (get board :rdia_occupied)
  (+ (- x y) (- (get board :nqueens) 1))) 0)
  )
)

; Print out the board contents
(defn printboard [board]
  (let [nq (get board :nqueens)]
(doseq [i (range 0 nq)] (print **))
(println )
(doseq [qiy (range 0 nq)]
(let [qx (- (nth (get board :yrow_occupied) qiy) 1)]
  (doseq [x (range 0 qx)] (print  -))
  (print  Q)
  (doseq [x (range (+ qx 1) nq)] (print  -))
  (println )
)
)
(doseq [i (range 0 nq)] (print **))
(println )
  )
)

; Following are set to run-time values in mainfunc
(def NQUEENS nil)
(def THREADDEPTH nil)
(def IS_PRINT nil)
(def IS_COUNT_THREADS nil)
(def NUMSOLUTIONS (atom 0))   ; Counts solutions across threads.
(def THCOUNTERS (atom nil))   ; Vector of thread counters, see
mainfunc.

(defn printsolution [mystate]
  (do
(swap! NUMSOLUTIONS (fn [oldval] (+ oldval 1)))
(if IS_PRINT (printboard mystate))
  )
)

(defn solve [instate mycolumn]
  (doseq [myrow (range 0 NQUEENS)]
(if (issafe instate mycolumn myrow)
  (let [newstate (nextboardstate instate mycolumn myrow (+
mycolumn 1))]
(if (== mycolumn (- NQUEENS 1))
  (printsolution newstate)
  (solve newstate (+ mycolumn 1))
)
  )
)
  )
)

(defn countThreads [thdepth thcount]
  ;(println DEPTH thdepth COUNT thcount)
  (swap! THCOUNTERS (fn [oldval]
 (assoc oldval thdepth (+ (nth oldval thdepth) thcount
)

; ARGHHH!!! with-local-vars blows up with a NullPointerException
; from the runtime when the with-local-vars block terminates,
; regardless of nesting level, apparently trashing the stack.
; So does the binding command for creating mutable local VARS.
; I could probably rebind symbols using loop-recur, but it is
; clumsier than just using tail recursion, so I am replacing
; the following broken thsolve with a tail recursive verison below.
;(defn thsolve [instate mycolumn thdepth]
; (with-local-vars [thlocalcntr 0 thlocalfutures (seq nil)]
;  (if (or ( thdepth 1) (== mycolumn (- NQUEENS 1)))
;

Re: bugs in with-local-vars and lexically-nested-function access to outer function parameters

2010-08-02 Thread Mark Engelberg
Can you distill this down to the smallest possible example that demonstrates
the error?

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