I have strange problem with type inference in Clojure. I have following
code (simplified version of real code),
(defn- process-char [#^InputStream istream]
(let [ch (.read istream)]
(if (= ch 10)
"AAA"
ch)))
(defn- process-text [#^InputStream istream]
(loop [char (.read istream)]
(let [result (process-char istream)]
(cond
;; .. some additional conditions
(string? result) (loop (.read istream))
(number? result) (loop result)
...))))
Main idea, that in some function, i read characters in sequence, and check
their values, and in some conditions, i need to re-submit already readed
character into loop, but when i use code above, i get following error:
java.lang.IllegalArgumentException: recur arg for primitive local: char must be matching primitive
[Thrown class java.lang.RuntimeException]
but if i replace (loop result) with (.read istream), then it works without
any problems
I checked type of result, and it's Integer - same type, that 'char' var in
loop will get after reading from stream.
If need, i can submit somebody full test case
--
With best wishes, Alex Ott, MBA
http://alexott.blogspot.com/ http://xtalk.msk.su/~ott/
http://alexott-ru.blogspot.com/
On Dec 30, 12:53 pm, Alex Ott <alex...@gmail.com> wrote:
>
> If need, i can submit somebody full test case
I think this might help because it's hard to tell what you are trying
to do without a little more context.
Some odd things that stand out to me:
1) You call loop, but you should be calling recur. E.g. (loop result)
2) Why are the arguments streams and not readers?
3) You do nothing with the 'char' variable binding.
My guess is you just made some typos while trying to create a simple
example.
Nikolay Petrov at "Wed, 30 Dec 2009 18:13:13 +0000" wrote:
NP> Is process char returns char or String?
I want to return either String, either Integer, depending on condition...
I'm sorry, i tried to prepare shorter example, and mixed loops & recurs.
Full example is attached. This is code, that implements something like
'strings' command on Unixes, but for UTF-8 encoding
The problem is, that i need to return from function 'read-utf-char', either
String, either Integer, depending on condition. Or this is not allowed by
Clojure? I mostly programming in Scheme, that allows such tricks
.Bill Smith at "Wed, 30 Dec 2009 11:28:54 -0800 (PST)" wrote:
.S> Sorry, I'm confused by the code sample. I see several loops but no
.S> corresponding recurs.
It's certainly ok for a function to return different data types. I
guess the simplest example of that would be the identity function.
user=> (identity 5)
5
user=> (identity "x")
"x"
Here is another one:
user=> (defn return-string-or-num [flag] (if flag "x" 0))
#'user/return-string-or-num
user=> (return-string-or-num :t)
"x"
user=> (return-string-or-num nil)
0
Here is an example of using that function with recur:
user=> (loop [x 0
count 0]
(println "x=" x "x is a" (class x) "count=" count)
(if (< count 10)
(recur (return-string-or-num (even? count))
(inc count))))
x= 0 x is a java.lang.Integer count= 0
x= x x is a java.lang.String count= 1
x= 0 x is a java.lang.Integer count= 2
x= x x is a java.lang.String count= 3
x= 0 x is a java.lang.Integer count= 4
x= x x is a java.lang.String count= 5
x= 0 x is a java.lang.Integer count= 6
x= x x is a java.lang.String count= 7
x= 0 x is a java.lang.Integer count= 8
x= x x is a java.lang.String count= 9
x= 0 x is a java.lang.Integer count= 10
nil
user=>
.Bill Smith at "Thu, 31 Dec 2009 09:20:16 -0800 (PST)" wrote:
.S> I tried out your example with a couple of files and it appeared to
.S> work. Is it supposed to fail, or is this an example of what you had
.S> to do to work around the problem you mentioned?
Yes, this is working variant
if you'll replace '(.read ireader)' in 'recur' on line 80 with 'res', then
it will fail.
.S> It's certainly ok for a function to return different data types. I
.S> guess the simplest example of that would be the identity function.
thanks for identity example, i'll look to it
P.S. Happy New Year to you, and rest of clojure community
--
I reproduced the problem as follows:
user=> (loop [x (byte 0) count 0]
(if (< count 10) (recur 0 (inc count))))
java.lang.RuntimeException: java.lang.IllegalArgumentException: recur
arg for primitive local: x must be matching primitive (NO_SOURCE_FILE:
57)
user=>
If the compiler detects that a loop binding evaluates to a primitive,
it insists that the corresponding recur argument be a reducible to a
primitive as well. You can short-circuit that logic with a type hint,
like this:
user=> (loop [x #^Object (byte 0)]
(if (< x 10) (recur (inc x))))
nil
user=>
It's ugly but it works. If you change line 65 in your example from
"char (.read ireader)]" to "char #^Object (.read ireader)]", the
compile error should go away. The example in my previous posting
didn't have that problem because 0 by itself is an Integer object, not
an int primitive.
On Dec 31 2009, 12:45 pm, Alex Ott <alex...@gmail.com> wrote:
> Hello Bill
>
> .Bill Smith at "Thu, 31 Dec 2009 09:20:16 -0800 (PST)" wrote:
> .S> I tried out your example with a couple of files and it appeared to
> .S> work. Is it supposed to fail, or is this an example of what you had
> .S> to do to work around the problem you mentioned?
>
> Yes, this is working variant
>
> if you'll replace '(.read ireader)' in 'recur' on line 80 with 'res', then
> it will fail.
>
> .S> It's certainly ok for a function to return different data types. I
> .S> guess the simplest example of that would be the identity function.
>
> thanks for identity example, i'll look to it
>
> P.S. Happy New Year to you, and rest of clojure community
>
> --
.Bill Smith at "Fri, 1 Jan 2010 10:44:37 -0800 (PST)" wrote:
.S> Happy New Year to you, Alex.
.S> I reproduced the problem as follows:
.S> user=> (loop [x (byte 0) count 0]
.S> (if (< count 10) (recur 0 (inc count))))
.S> java.lang.RuntimeException: java.lang.IllegalArgumentException: recur
.S> arg for primitive local: x must be matching primitive (NO_SOURCE_FILE:
.S> 57)
.S> user=>
.S> If the compiler detects that a loop binding evaluates to a primitive,
.S> it insists that the corresponding recur argument be a reducible to a
.S> primitive as well. You can short-circuit that logic with a type hint,
.S> like this:
.S> user=> (loop [x #^Object (byte 0)]
.S> (if (< x 10) (recur (inc x))))
.S> nil
.S> user=>
.S> It's ugly but it works. If you change line 65 in your example from
.S> "char (.read ireader)]" to "char #^Object (.read ireader)]", the
.S> compile error should go away. The example in my previous posting
.S> didn't have that problem because 0 by itself is an Integer object, not
.S> an int primitive.
--