Free book on Clojure (in German)

2013-04-16 Thread Dominikus
If you speak German, I have a free book on Clojure (Funktionale 
Programmierung in Clojure) for you:

http://denkspuren.blogspot.de/2013/04/freies-clojure-buch-funktionale.html

Dominikus

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




Clojure and the Anti-If Campaign

2012-05-24 Thread Dominikus
Three weeks ago I stumbled across the Anti-If Campaign (
http://www.antiifcampaign.com/).

An instant later I realized that one could easily re-implement if in 
Clojure with maps. More interestingly, polymorphic functions can be easily 
motivated with the help of maps. And this naturally leads to multimethods.

If you like, enjoy reading my blogpost on The root of polymorphism: The 
Anti-If Campaign. It might be an interesting read for Clojure enthusiasts.

http://denkspuren.blogspot.de/2012/05/root-of-polymorphism-anti-if-campaign.html
 

Cheers,

Dominikus


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

Bug recognizing tail position as default value in maps?

2012-04-27 Thread Dominikus
Is suspect this being a bug: When a recursive function call is used as a 
default value in a map, its tail position is not recognized. The problem 
can be easily demonstrated using the fixpoint function. The fixpoint 
function is usually defined as

 (defn fix [f x] (let [v (f x)] (if (= v x) x (recur f v  

To avoid the 'if' special form, we can use a map. The compiler rejects 
compilation and does not recognize (recur f v) to be correctly in tail 
position.

 (defn fix2 [f x] (let [v (f x)] ({x x} v (recur f v
CompilerException java.lang.UnsupportedOperationException: Can only recur 
from t
ail position, compiling:(NO_SOURCE_PATH:41)

Avoiding tail recursion lets fix2 compile but not execute properly:

 (defn fix2 [f x] (let [v (f x)] ({x x} v (fix2 f v
#'user/fix2
 (fix identity 1)
1
 (fix2 identity 1)
StackOverflowError   user/fix2 (NO_SOURCE_FILE:44)

Strange, isn't it!?

Dominikus

-- 
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: Bug recognizing tail position as default value in maps?

2012-04-27 Thread Dominikus
Sure? The semantics of the default value corresponds to a 'if', doesn't it? 
From this viewpoint, the default value is in tail position. And why does 
the non-tailrecursive version not run as expected?

Dominikus 


Am Freitag, 27. April 2012 16:45:44 UTC+2 schrieb Meikel Brandmeyer 
(kotarak):

 Hi,

 (defn fix2 [f x] (let [v (f x)] ({x x} v (recur f v

 recur is not in the tail position. The call to the map is the tail call. 
 So the result is as expected.

 Kind regards,
 Meikel



-- 
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: Bug recognizing tail position as default value in maps?

2012-04-27 Thread Dominikus
I got it, guys! Thanks a lot! This non-tailrecursive version works as 
intended:

(defn fix2 [f x] (let [y (f x)] (eval ({x x} y (list 'fix2 f y)

Dominikus

Am Freitag, 27. April 2012 17:00:52 UTC+2 schrieb Luke VanderHart:

 Using a map instead of if means that it is evaluated as a function call. 
 Unlike the if form, function calls eval their arguments. So the (recur) 
 form is getting eval'd prior to being passed to the map/function, which 
 isn't a tail position.

 That's why if is a special form/macro, not a regular function (like maps 
 are).

 On Friday, April 27, 2012 10:52:10 AM UTC-4, Dominikus wrote:

 Sure? The semantics of the default value corresponds to a 'if', doesn't 
 it? From this viewpoint, the default value is in tail position. And why 
 does the non-tailrecursive version not run as expected?

 Dominikus 


 Am Freitag, 27. April 2012 16:45:44 UTC+2 schrieb Meikel Brandmeyer 
 (kotarak):

 Hi,

 (defn fix2 [f x] (let [v (f x)] ({x x} v (recur f v

 recur is not in the tail position. The call to the map is the tail 
 call. So the result is as expected.

 Kind regards,
 Meikel



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

Contagious BigInts in 1.3? Why is (type (- 2 1N)) java.lang.Long?

2011-09-08 Thread Dominikus
In Clojure 1.3, BigInts are said to be contagious across operations.


When different types of numbers are used in a math operation, the
result will be the larger or more general of the two types. For
example, any integer operation involving a BigInt will result in a
BigInt, [...].

http://dev.clojure.org/display/doc/Documentation+for+1.3+Numerics

However (type (- 2 1N)) results in java.lang.Long and does not seem to
work accordingly. What's going on here?

Cheers,

Dominikus

-- 
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: Contagious BigInts in 1.3? Why is (type (- 2 1N)) java.lang.Long?

2011-09-08 Thread Dominikus
Thanks, Eric. My original problem was the factorial function, which
breaks despite using BigInts:

user= (defn fact [n] (if (= n 1N) 1N (* n (fact (- n 1N)
#'user/fact
user= (type (fact 1))
clojure.lang.BigInt
user= (type (fact 20))
java.lang.Long
user= (type (fact 21))
ArithmeticException integer overflow
clojure.lang.Numbers.throwIntOverflow (Num
bers.java:1374)

The optimization to using Longs seems to be too aggressive. Upgrade
casting in Clojure 1.2 is cool and simple.

Dominikus

On Sep 8, 1:30 pm, Eric Lavigne lavigne.e...@gmail.com wrote:
 You have discovered a very recent change. The idea is to automatically
 switch to longs for performance when it is clear that overflow will
 not occur.

      https://github.com/clojure/clojure/commit/684fca15040e1ec8753429909b2...

 There are still some problems with this optimization, which will
 hopefully be worked out before the final 1.3 release.

      http://dev.clojure.org/jira/browse/CLJ-836







 On Thu, Sep 8, 2011 at 6:25 AM, Dominikus dominikus.herzb...@gmail.com 
 wrote:
  In Clojure 1.3, BigInts are said to be contagious across operations.

  
  When different types of numbers are used in a math operation, the
  result will be the larger or more general of the two types. For
  example, any integer operation involving a BigInt will result in a
  BigInt, [...].
  
 http://dev.clojure.org/display/doc/Documentation+for+1.3+Numerics

  However (type (- 2 1N)) results in java.lang.Long and does not seem to
  work accordingly. What's going on here?

-- 
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: Contagious BigInts in 1.3? Why is (type (- 2 1N)) java.lang.Long?

2011-09-08 Thread Dominikus
Right, this feature is documented in 
http://dev.clojure.org/display/doc/Documentation+for+1.3+Numerics

For me it feels somewhat strange to use primed operations to enforce
upgrade casting and to write a special faculty function for that.

I just discovered that (fact 21) breaks while (fact 21N) does not but
(fact 22N) does:

user= (defn fact [n] (if (= n 1) 1 (* n (fact (- n 1)
#'user/fact
user= (fact 21)
ArithmeticException integer overflow
clojure.lang.Numbers.throwIntOverflow (Num
bers.java:1374)
user= (fact 21N)
5109094217170944N
user= (fact 22N)
ArithmeticException integer overflow
clojure.lang.Numbers.throwIntOverflow (Num
bers.java:1374)

Weird!

Dominikus

On Sep 8, 2:05 pm, Meikel Brandmeyer (kotarak) m...@kotka.de
wrote:
 Hi,

 Am Donnerstag, 8. September 2011 13:57:49 UTC+2 schrieb Dominikus:



  Upgrade casting in Clojure 1.2 is cool and simple.

 It's also in 1.3 cool and simple.

 user= (defn fact [n] (if (= n 1N) 1N (* n (fact (- n 1N)
 #'user/fact
 user= (fact 21)
 ArithmeticException integer overflow  clojure.lang.Numbers.throwIntOverflow
 (Numbers.java:1374)
 user= (defn fact' [n] (if (= n 1N) 1N (*' n (fact (dec n)
 #'user/fact'
 user= (fact' 21)
 5109094217170944N

 Sincerely
 Meikel

-- 
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: Contagious BigInts in 1.3? Why is (type (- 2 1N)) java.lang.Long?

2011-09-08 Thread Dominikus
Thanks for the explanation, Meikel!

I'll wait for the next release which hopefully fixes the bug.

Cheers,

Dominikus

On Sep 8, 2:31 pm, Meikel Brandmeyer (kotarak) m...@kotka.de
wrote:
 Hi,

 Am Donnerstag, 8. September 2011 14:21:09 UTC+2 schrieb Dominikus:



  Right, this feature is documented in
 http://dev.clojure.org/display/doc/Documentation+for+1.3+Numerics

  For me it feels somewhat strange to use primed operations to enforce
  upgrade casting and to write a special faculty function for that.

 This is the trade-off between safe/fast and safe/slow.

  I just discovered that (fact 21) breaks while (fact 21N) does not but
  (fact 22N) does:

  Weird!

 This is due to the fact, that the overflow in (fact 21) happens in the *.
 With (fact 21N) this works because the 21N promotes the * to a BigInt
 operation and (fact 20) still fits into a long. So everything works here.
 With (fact 22N) the (- 22N 1) demotes the 21 to a long (-- Here is the bug)
 since it small enough to fit in there. Then we are in the (fact 21)
 situation again.

 Please keep in mind, that this behaviour is due to a bug in the current
 BigInt implementation! Normally a (fact 21N) would just work. The BigInt
 should use long arithmetic internally if possible. But the re-promotion to
 a real BigInt doesn't work correctly.

 Sincerely
 Meikel

-- 
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: Why do transactions block each other?

2011-09-05 Thread Dominikus
Right, it's according to the spec, but it doesn't explain the
behavior. as I noticed this morning http://clojure.org/refs references
http://en.wikipedia.org/wiki/Multiversion_concurrency_control (the
technique used to implement STM) which provides an explanation for the
experienced behavior:

quote
If a transaction (Ti) wants to write to an object, and if there is
another transaction (Tk), the timestamp of Ti must precede the
timestamp of Tk (i.e., TS(Ti)  TS(Tk)) for the object write operation
to succeed. Which is to say a write cannot complete if there are
outstanding transactions with an earlier timestamp.
/quote

That's why the second transaction, which comes later in time, is the
one waiting for the first transaction to complete.

Dominikus

On Aug 30, 9:53 am, Laurent PETIT laurent.pe...@gmail.com wrote:
 2011/8/30 Kevin Downey redc...@gmail.com

  the two threads race to acquire the write lock and the winner runs,
  the loser retries. my guess is acquiring the write lock helps avoid
  live locks between transactions.

 Yes, and after re-readinghttp://clojure.org/refs, the current behaviour
 does not seem to violate any of the 10 guaranteed listed points.

 So, while it seems unfortunate from client's code point of view, it is
 correct wrt to the current specs.

 Now I more deeply understand why one should at all price avoid long
 computations from within a transaction ...

 Cheers,

 --
 Laurent









  On Mon, Aug 29, 2011 at 10:59 PM, Laurent PETIT laurent.pe...@gmail.com
  wrote:
   My tests were false.
   Since I sent the code at once to the REPL, there was a race condition
   between the start of the agent and the dosync for setting the ref's value
  to
   2000 ; this explains the weirdness of my test results (thank you, Mr
  Murphy,
   for having made the tests look like beta2 behaved differently from the
   others ...)
   So now I see consistent behaviours across 1.2.0, beta1 and beta2.
   But I am still perplex and confused by the behaviour ...

   2011/8/30 Laurent PETIT laurent.pe...@gmail.com

   ok so now i'm totally confused, since I cannot see why the behaviour is
  so
   different between beta1 and beta 2 ...

   2011/8/30 Laurent PETIT laurent.pe...@gmail.com

   Congratulations, you've found a bug in clojure 1.3 beta2, see:
    look with my clojure 1.2.0 version :
   ;; Clojure 1.2.0
   = (def thread (agent Thread))
      (def account (ref 1000))
      (send thread
            (fn [agt aref] (dosync (alter aref + 100) (Thread/sleep 8000)
   agt))
            account)
      (time (dosync (ref-set account 2000)))
   #'user/thread
   #'user/account
   #Agent@7e543cb1: Thread
   Elapsed time: 0.498106 msecs
   2000
   = ;; 10 seconds later :
   = @account
   2100

   And now with clojure 1.3 beta1 :
   ;; Clojure 1.3.0-beta1
   = (def thread (agent Thread))
      (def account (ref 1000))
      (send thread
            (fn [agt aref] (dosync (alter aref + 100) (Thread/sleep 8000)
   agt))
            account)
      (time (dosync (ref-set account 2000)))
      ;; 10 seconds later :
   #'user/thread
   #'user/account
   #Agent@6bf51e5c: Thread
   Elapsed time: 0.270225 msecs
   2000
   = @account
   2100
   And now with Clojure 1.3-beta2
   ;; Clojure 1.3.0-beta2
   = (def thread (agent Thread))
      (def account (ref 1000))
      (send thread
            (fn [agt aref] (dosync (alter aref + 100) (Thread/sleep 8000)
   agt))
            account)
      (time (dosync (ref-set account 2000)))
   #'user/thread
   #'user/account
   #Agent@50fba502: Thread
   Elapsed time: 7957.328798 msecs
   2000
      ;; 10 seconds later :
   = @account
   2000
      ;; 10 more seconds later :
   = @account
   2000
   2011/8/30 Laurent PETIT laurent.pe...@gmail.com

   2011/8/29 Dominikus dominikus.herzb...@gmail.com

   Thanks a lot for this detailed analysis and the pointers to the Java
   implementation, Stefan! That's excellent and very helpful.

   I still wonder, why the first transaction blocks write access. My
   overall understanding of the transaction system is that changes to
   referenced values remain in-transaction before committing them, a
   write-lock shouldn't be needed. I'm surprised, that the second
   transaction is the one who has to retry 71 times even though the
  first
   transaction hasn't committed anything yet.

   I must confess this behaviour also challenges my assumptions.
   Does this work the same whatever the clojure version used ?

   Cheers,

   Dominikus

   P.S.: Thanks for the idea to use 'future' to spawn a thread!

   On Aug 29, 5:42 pm, Stefan Kamphausen ska2...@googlemail.com
  wrote:
The call to alter already wrote to the Ref, this requires a
write-lock on
the ref (see LockingTransaction.java/doSet).  After that it sleeps
  a
while
and gets to its commit phase.  The other transactions retries in
  the
meantime.  Consider the following code, which introduces some atoms
for
counting the retries

(defn tz []
  (let [rr (ref

Re: Why do transactions block each other?

2011-09-05 Thread Dominikus
That's a cool link and an interesting read! Thanks, Stefan!

Dominikus

On Sep 5, 10:23 pm, Stefan Kamphausen ska2...@googlemail.com wrote:
 Hi,

 there is another paper in the wild which very nicely describes, how
 Clojure's implementation of STM works and how it compares to other
 management strategies for resolving conflicts.

 http://vbn.aau.dk/files/32587755/report.pdf

 Definitely worth a read, I think.

 Best,
 Stefan

-- 
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: Why do transactions block each other?

2011-08-29 Thread Dominikus
Thanks a lot for this detailed analysis and the pointers to the Java
implementation, Stefan! That's excellent and very helpful.

I still wonder, why the first transaction blocks write access. My
overall understanding of the transaction system is that changes to
referenced values remain in-transaction before committing them, a
write-lock shouldn't be needed. I'm surprised, that the second
transaction is the one who has to retry 71 times even though the first
transaction hasn't committed anything yet.

Cheers,

Dominikus

P.S.: Thanks for the idea to use 'future' to spawn a thread!

On Aug 29, 5:42 pm, Stefan Kamphausen ska2...@googlemail.com wrote:
 The call to alter already wrote to the Ref, this requires a write-lock on
 the ref (see LockingTransaction.java/doSet).  After that it sleeps a while
 and gets to its commit phase.  The other transactions retries in the
 meantime.  Consider the following code, which introduces some atoms for
 counting the retries

 (defn tz []
   (let [rr (ref 10)
         a1 (atom 0)
         a2 (atom 0)]
     (println Starting future)
     (future
      (dosync
       (swap! a1 inc)
       (alter rr + 100)
       (Thread/sleep 8000)))
     (println Sleeping a bit)
     (Thread/sleep 1000)
     (println Another dosync)
     (time
      (dosync
       (swap! a2 inc)
       (ref-set rr 1)))
     [@rr @a1 @a2 (.getHistoryCount rr)]))

 user (tz)
 Starting future
 Sleeping a bit
 Another dosync
 Elapsed time: 7001.554 msecs
 [1 1 71 0]

 Note, how the 71 retries nice fit the approximately 7 seconds left and the
 100 miliseconds time-out (LOCK_WAIT_MSECS)  for the lock used in
 LockingTransaction.java/tryWriteLock.

 Transactions with significantly different run-times should be avoided,
 although there is some point at which older transactions will get their
 turn.  This could be another explanation of the effect.  Take a look at the
 barge-function in LockingTransaction.java

 Hope this helps,
 Stefan

-- 
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: Eval destroys equality

2011-05-06 Thread Dominikus
On May 6, 8:39 pm, Adam Burry abu...@gmail.com wrote:
 On May 6, 3:10 pm, Andy Fingerhut andy.finger...@gmail.com wrote:

  Caveat: The following fact may already be well known to those discussing 
  this issue, and I may not be clear on the goal of this effort.

  If the goal is to have functions compare as equal whenever they are 
  equivalent in some sense, then that is an undecidable problem, even if the 
  two functions are restricted to pure functions with no side effects and 
  closed over no vars.  The proof is nearly the same as that for the halting 
  problem.

  Of course, it is still decidable to get the correct answer for some 
  restricted kinds of functions.  If that is what you are after, go for it.

 I don't think anyone expects quick sort to compare equal to bubble
 sort or anything like that. I think the issue is to get two functions
 with the same textual representation to compare equal.

 Adam

Right, Adam. As Armando pointed out, Clojure 1.3 at least doesn't fail
in the case I brought up. I would be very interested to learn what has
changed in the Clojure 1.3 source code (compared to 1.2) to achieve
this.

Dominikus

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


Eval destroys equality

2011-05-05 Thread Dominikus
My observation is best distilled with the following definition of a
function in Clojure 1.2:

user= (defn id [x] (list id x))
#'user/id

Interstingly, (id 7) and (eval (id 7)) result in different instances
of function id as the number after the '@' char unveils:

user= (id 7)
(#user$id user$id@53797795 7)
user= (eval (id 7))
(#user$id user$id@2de12f6d 7)

Consequently, the following comparison leads to false:

user= (= (id 7) (eval (id 7)))
false

Why is the instance relevant to '='? What is the precise semantics of
two values being equal in Clojure?

Dominikus

(Remark: In Scheme, the use of 'eqv?' returns also #f, but the less
restrictive 'equal?' does not and returns #t.)

-- 
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: Eval destroys equality

2011-05-05 Thread Dominikus Herzberg
Thanks a lot, Armando. Looks like I should switch to Clojure 1.3 asap.

Cheers,

Dominikus

2011/5/5 Armando Blancas armando_blan...@yahoo.com:
 In 1.3 the function will (eval) to itself:

 Clojure 1.3.0-alpha6
 user= (defn id [x] (list id x))
 #'user/id
 user= (id 7)
 (#user$id user$id@3411a 7)
 user= (eval (id 7))
 (#user$id user$id@3411a 7)
 user= (= (id 7) (eval (id 7)))
 true

 On May 5, 6:04 am, Dominikus dominikus.herzb...@gmail.com wrote:
 My observation is best distilled with the following definition of a
 function in Clojure 1.2:

 user= (defn id [x] (list id x))
 #'user/id

 Interstingly, (id 7) and (eval (id 7)) result in different instances
 of function id as the number after the '@' char unveils:

 user= (id 7)
 (#user$id user$id@53797795 7)
 user= (eval (id 7))
 (#user$id user$id@2de12f6d 7)

 Consequently, the following comparison leads to false:

 user= (= (id 7) (eval (id 7)))
 false

 Why is the instance relevant to '='? What is the precise semantics of
 two values being equal in Clojure?

 Dominikus

 (Remark: In Scheme, the use of 'eqv?' returns also #f, but the less
 restrictive 'equal?' does not and returns #t.)

 --
 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: Eval destroys equality

2011-05-05 Thread Dominikus
Thanks for the pointers to the implementation, Jonathan!

Unfortunately, I couldnt' find out yet, which part of the source code
in Clojure 1.3 is responsible for fixing the misbehavior in 1.2. The
parts you point to haven't changed in 1.3.

Cheers,

Dominikus

On May 5, 4:27 pm, Jonathan Fischer Friberg odysso...@gmail.com
wrote:
 = uses the clojure.lang.Util/equiv to compare two things. The source of
 this function is: [1]

 static public boolean equiv(Object k1, Object k2){
         if(k1 == k2)
                 return true;
         if(k1 != null)
                 {
                 if(k1 instanceof Number  k2 instanceof Number)
                         return Numbers.equiv(k1, k2);
                 else if(k1 instanceof IPersistentCollection  k2 instanceof
 IPersistentCollection)
                         return ((IPersistentCollection)k1).equiv(k2);
                 return k1.equals(k2);
                 }
         return false;

 }

 Which says:
 if k1 and k2 is the same instance (has the same id), return true
 if k1 and k2 are numbers, compare them as numbers
 if k1 and k2 are collections, compare them as collections
 otherwise, use the function equals of the k1 object.

 The equals function defines intelligent (proper) comparison of two
 objects, and is defined by the programmer. If the equals function isn't
 defined, it behaves like == [2]
 The == function returns true if the things are of the same instance.

 I think functions in clojure are defined in [3], but I'm not entirely sure.
 As you can see, equals isn't implemented, and thus = will only compare
 instance (id), as you have noticed.

 Jonathan

 [1]https://github.com/richhickey/clojure/blob/master/src/jvm/clojure/lan...
 https://github.com/richhickey/clojure/blob/master/src/jvm/clojure/lan...
 [2]http://leepoint.net/notes-java/data/expressions/22compareobjects.html
 [3]https://github.com/richhickey/clojure/blob/master/src/jvm/clojure/lan...

 On Thu, May 5, 2011 at 3:04 PM, Dominikus dominikus.herzb...@gmail.com
 wrote:









  My observation is best distilled with the following definition of a
  function in Clojure 1.2:

  user= (defn id [x] (list id x))
  #'user/id

  Interstingly, (id 7) and (eval (id 7)) result in different instances
  of function id as the number after the '@' char unveils:

  user= (id 7)
  (#user$id user$id@53797795 7)
  user= (eval (id 7))
  (#user$id user$id@2de12f6d 7)

  Consequently, the following comparison leads to false:

  user= (= (id 7) (eval (id 7)))
  false

  Why is the instance relevant to '='? What is the precise semantics of
  two values being equal in Clojure?

  Dominikus

  (Remark: In Scheme, the use of 'eqv?' returns also #f, but the less
  restrictive 'equal?' does not and returns #t.)

  --
  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: Evaluation of Symbol Bindings vs. Special Forms

2011-03-15 Thread Dominikus
You are right, Ken. I was a little bit sloppy regarding macro
expansion. The macroexpand1 method (line 5275) called by analyzeSeq
quits immediately, if the operator is a special symbol. Thus, 'if'
cannot be overwritten by a macro as you demonstrated with your if-
defmacro example, only the use of a qualified name can.

Regarding your qqq-defmacro example, you seem to be onto something.
From reading the code in Compiler.java, I don't get (yet), why this
does not work as expected, but there is a comment left in method
analyze saying in line 5155:

// todo symbol macro expansion?

Maybe that's the issue here. Possibly, some code is missing covering
your case.

Interestingly, macroexpand does not work on your qqq-macro either:

user= (macroexpand '((qqq) (even? 42) boo!))
((qqq) (even? 42) boo!)

That's weird.

Dominikus

On 15 Mrz., 01:24, Ken Wesson kwess...@gmail.com wrote:
 On Mon, Mar 14, 2011 at 6:32 PM, Dominikus dominikus.herzb...@gmail.com 
 wrote:
  I did some investigations on the code in Compiler.java. There is an
  IPersistentMap called 'specials' (line 95, Clojure 1.2) that maps
  symbols like 'if' to parsers like IfExpr.Parser(); obviously, these
  are the parsers recognizing special forms.

  Method analyzeSeq (line 5347) tries macro expansion first and gets the
  operator of a sequence form next. There is some special behavior if
  the operator is FN (namely 'fn*' for which no parser is associated in
  'specials'; I don't know why 'fn*' gets special treatment here), then
  special parsers are activated if the operator is a special symbol,
  otherwise InvokeExpr.parse() is run.

 That doesn't quite seem right:

 user= (defmacro if [x y] `(println ~x ~y))
 #'user/if
 user= (if (even? 42) boo!)
 boo!
 user= (user/if (even? 42) boo!)
 true boo!
 nil
 user=

 Clearly, the if special symbol, when in operator position, shadows
 even macros, forcing the use of a fully-qualified name to employ a
 macro named if.

 Perhaps you meant it does macroexpansion of the subforms first, but
 not (yet) of the whole form? Then it checks for the whole form to be a
 special form; then for the whole form to be a macro in need of
 expansion; and then treats it as a function call.

 If so, it's only the subforms not in operator position that get
 macroexpanded first. Otherwise

 user= (defmacro qqq [] 'if)
 #'user/qqq
 user= ((qqq) (even? 42) boo!)
 #CompilerException java.lang.Exception: Unable to resolve symbol: if
 in this context (NO_SOURCE_FILE:607)

 would instead produce boo!, as (qqq) would be expanded to if and
 then (if (even? 42) boo!) would be parsed and discovered to be an if
 special form.

 On the other hand,

 user= (quote (qqq))
 (qqq)

 seems to indicate that nothing is macroexpanded before special form
 parsing occurs, or it would have output if instead of (qqq), unless
 quote it another special case.

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


Evaluation of Symbol Bindings vs. Special Forms

2011-03-14 Thread Dominikus
I'm not sure I fully understand symbol resolution and the evaluation
strategy of symbol bindings and special forms in Clojure 1.2.

Let's say I bind 'if' (usually being a special form) to a function:

user= (defn if [x] (* x x))
#'user/if

However, calling 'if' with an unqualified name does not work. Still,
'if' works like a special form:

user= (if 3)
java.lang.Exception: Too few arguments to if (NO_SOURCE_FILE:74)
user= (if true 1 2)
1

However, 'if' itself evaluates to the new function on the REPL:

user= if
#user$if user$if@118d189

But I can call the redefined 'if' only with a qualified symbol name

user= (user/if 3)
9

Why is that? I find it inconsistent to see 'if' evaluating to a
function in the REPL but not in the context of a list; in a list form
I'm forced to use a qualified name to suppress interpretation as a
special form. What is the precise evaluation strategy? (I know, it's
dangerous to redefine special forms. Here, I'm interested in the
evaluation strategy of special forms vs. bound symbols.)

Cheers,

Dominikus

-- 
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: Evaluation of Symbol Bindings vs. Special Forms

2011-03-14 Thread Dominikus
This was also my best guess, Timothy and Stuart, but it does not
explain why a redefined 'if' (or a competing symbol binding, Stuart?)
in the REPL leads to

user= if
#user$if user$if@118d189

while 'if' within a list form does not:

user= (if 3)
java.lang.Exception: Too few arguments to if (NO_SOURCE_FILE:74)

I think this is an inconsistent interaction model -- it might even
hint towards an implementation flaw. If I manually decompose a list
form and analyze its elements in isolation (first evaluate 'if' and
then '3' in the REPL), the composite list form should behave
accordingly, shouldn't it?

I come up with this scenario in order to understand the precise
behavior of Clojure's evaluation strategy regarding symbol bindings
and special forms. As I said, I'm fully aware that it's no good idea
to change 'if' or any other special forms in production code.

Dominikus

On 14 Mrz., 18:26, Stuart Sierra the.stuart.sie...@gmail.com wrote:
 Yes, with one correction: Clojure is not an interpreter.  The Clojure
 compiler treats certain symbols specially, such as `if`, `do`, and `def`.
  You cannot redefine these symbols.

 -Stuart Sierra
 clojure.com

-- 
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: Evaluation of Symbol Bindings vs. Special Forms

2011-03-14 Thread Dominikus
I did some investigations on the code in Compiler.java. There is an
IPersistentMap called 'specials' (line 95, Clojure 1.2) that maps
symbols like 'if' to parsers like IfExpr.Parser(); obviously, these
are the parsers recognizing special forms.

Method analyzeSeq (line 5347) tries macro expansion first and gets the
operator of a sequence form next. There is some special behavior if
the operator is FN (namely 'fn*' for which no parser is associated in
'specials'; I don't know why 'fn*' gets special treatment here), then
special parsers are activated if the operator is a special symbol,
otherwise InvokeExpr.parse() is run. All this works as expected.

Method analyze (line 5154) analyzes a given expression. If its a
symbol, then analyzeSymbol (line 5556) is called, if its a form of
kind ISeq, then analyzeSeq is called. There are more checks, of
course. As one can see in analyzeSymbol, bindings are resolved but
there is no check whether a special symbol like 'if' is used or not.

The analysis of the code confirms the behavior of a redefined i.e.
bound 'if' symbol. In favor of a consistent user experience (as
described in the previous post), it simply shouldn't be possible to
bind special symbols like 'if' to values at all. I guess that some few
lines in Compiler.java could fix that. I don't know how Lisp treats
this case.

Dominikus

On 14 Mrz., 22:09, Timothy Baldridge tbaldri...@gmail.com wrote:
 Yes, I think if you dig down into the Compiler.java code (that's where
 I assume this issue comes from) you'll probably find your answer.

 Recently in a blog entry Eric Lippert (one of the developers of C#)
 handled this exact subject. There are some 'bugs' in languages that
 exist, not because the developers don't know that they exist, but
 because actually reproducing the bug results in code that would never
 be used in production code. Sure this could be viewed as a bug, but
 who cares?

 Timothy







  I think this is an inconsistent interaction model -- it might even
  hint towards an implementation flaw. If I manually decompose a list
  form and analyze its elements in isolation (first evaluate 'if' and
  then '3' in the REPL), the composite list form should behave
  accordingly, shouldn'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