I'm learning Clojure. I wrote a first-attempt at calculating a Fibonacci number. Here's my code and the subsequent error message.
I have NO CLUE what to correct. My question is: WHAT is the error message trying to say?
(defn fibon
(fn [n]
(loop [loops n acc 1N acc2 0N]
(if (<= loops 0)
acc ;; Return the summed F number.
(recur (dec loops) (+ acc acc2) acc)))))
Syntax error macroexpanding clojure.core/defn at
(form-init1248982153229513778.clj:1:1). fn - failed: vector? at:
[:fn-tail :arity-n :bodies :params] spec:
:clojure.core.specs.alpha/param-list (fn [n] (loop [loops n acc 1N
acc2 0N] (if (<= loops 0) acc (recur (dec loops) (+ acc acc2) acc)))) failed: vector? at: [:fn-tail :arity-1 :params] spec: :clojure.core.specs.alpha/param-list
In general, could someone please point me to some documentation on Clojure in Cursive so I can decipher these error messages myself, if there is such a beast. Thank you.
The error message you see is a clojure.spec error. It is telling you that your code violates the specification of defn.
The error message is cryptic but if you unpack the error message you can see that the param-list clojure.spec failed because (fn [n] (loop ... is not a vector?
This is trying to tell you that defn expected to see a vector after fibon, not (fn [n] (loop ... It is not the most intuitive error message.
There is the clojure spec guide but it is targeted to developers of specifications.
There are other clojure projects that provide more intuitive spec error messages. I've used expound at the command line and it provides much nicer error messages, however I don't think you can use expound with cursive, but that might be worth exploring.
When I saw your code, I first looked at what the definiation of the defn macro is by doing a ctrl-mouse-over on the defn, or you can look at the online defn documentation. That information along with the spec error let me understand how to interpret the error message.
As for your code, when using defn you don't use (fn. So your code should look like:
(defn fibon [n]
(loop [loops n acc 1N acc2 0N]
(if (<= loops 0)
acc ;; Return the summed F number.
(recur (dec loops) (+ acc acc2) acc))))
The above answer is good. One suggestion to a question you didn't ask: you may wish to adjust your IDEA settings so it only indents 2 spaces each line, instead of 8 spaces (1 tab char?).
If necessary, uncheck the box "Use tab character". Here is a screenshot:
Then it will look like this:
(defn fibon
[n]
(loop [loops n
acc 1N
acc2 0N]
(if (<= loops 0)
acc ;; Return the summed F number.
(recur (dec loops) (+ acc acc2) acc))))
For the loop statement, I like to keep each loop variable and its initial value on a separate line. In this way it looks similar to the Clojure let expression.
Enjoy!
Related
I'm sure this is a very basic question, but how to output delimited values?
(defun q (n)
(if (<= n 2)
1
(+
(q (- n (q (- n 1))))
(q (- n (q (- n 2)))))))
(loop for x from 1 to 25
do (
write (q x)))
The above outputs the first 25 terms of the Hofstadter Q-sequence, but concatenated:
11233455666888109101111121212121614
Can be comma-, space- or tab-delimited. I tried playing with the format function, but it's way over my head for a Lisp newbie like me.
You can write the delimiter yourself, e. g. (write ", "). You can also write the (platform dependent) line separator with (terpri).
As for format, you can get by with some basic usage at first:
(format <stream> <template> <args…>)
<stream> is where the output should go. For standard output, use t. In order to write to a file, you would use the stream created by with-open-file here.
<template> is a template string. That's just a string, but the ~ character is special. For starters, just use ~a wherever you want to insert an argument.
<args…> are exactly as many further arguments as you used ~a above.
Using this simple toolbox, you could do: (format t "~a, " (q x)) for each item.
Format has a lot of other possibilities, e. g. it can iterate a list by itself, do different output formats and escaping, or even be extended by user functions. Look that up in the hyperspec (e. g. at clhs.lisp.se).
use write-char or, indeed, format:
(format t "~D: ~:D~%" x (q x))
I want to get two numbers from STDIN and print the sum of them to STDOUT. The following code is my solution:
#lang racket
(displayln (+ (string->number (string-trim (read-line)))
(string->number (string-trim (read-line)))))
If the input is
1
2
Sometimes the output is 3 as expected, but sometimes the output is:
+: contract violation
expected: number?
given: #f
argument position: 1st
other arguments...:
2
context...:
sum.rkt: [running body]
Why is that?
Edit 1
As shown in the following picture:
Edit 2
I wrote the following code to explore the behaviour of my program:
#lang racket
(displayln "Input:")
(define s1 (string-trim (read-line)))
(define s2 (string-trim (read-line)))
(displayln "Output:")
(displayln (string->list s1))
(displayln (string->list s2))
(define n1 (string->number (string-trim s1)))
(define n2 (string->number (string-trim s2)))
(displayln n1)
(displayln n2)
(displayln (+ n1 n2))
My computer is slow, so the Input: line needs some time to come out. If I wait until the line shows up before I type the inputs, the program will behave as I expect:
But if I don't wait for the Input: line and type in my inputs directly, sometimes the error will happen:
So now my questions are:
Does it mean that the error happens because Racket is not initialized yet?
What does R mean?
In the error case, why is the first input correctly interpreted as 1, but the second input wrongly interpreted as R?
(I'm running Racket v6.1.1 under Winodws 7 Pro SP1)
It's best to use (read) to read numbers, assuming you can rely on sane input (i.e., if it's actually going to be numbers and not garbage or, worse, massive S-expressions). Thus your code would be:
(displayln (+ (read) (read)))
I obtained the following code from Isabelle's wikipedia page:
theorem sqrt2_not_rational:
"sqrt (real 2) ∉ ℚ"
proof
assume "sqrt (real 2) ∈ ℚ"
then obtain m n :: nat where
n_nonzero: "n ≠ 0" and sqrt_rat: "¦sqrt (real 2)¦ = real m / real n"
and lowest_terms: "gcd m n = 1" ..
from n_nonzero and sqrt_rat have "real m = ¦sqrt (real 2)¦ * real n" by simp
then have "real (m²) = (sqrt (real 2))² * real (n²)" by (auto simp add: power2_eq_square)
also have "(sqrt (real 2))² = real 2" by simp
also have "... * real (m²) = real (2 * n²)" by simp
finally have eq: "m² = 2 * n²" ..
hence "2 dvd m²" ..
with two_is_prime have dvd_m: "2 dvd m" by (rule prime_dvd_power_two)
then obtain k where "m = 2 * k" ..
with eq have "2 * n² = 2² * k²" by (auto simp add: power2_eq_square mult_ac)
hence "n² = 2 * k²" by simp
hence "2 dvd n²" ..
with two_is_prime have "2 dvd n" by (rule prime_dvd_power_two)
with dvd_m have "2 dvd gcd m n" by (rule gcd_greatest)
with lowest_terms have "2 dvd 1" by simp
thus False by arith
qed
However, when I copy this text into an Isabelle instance, there are multiple 'do not enter' symbols to the left of each line. One says 'Illegal application of command "theorem" at top level' so I assumed that you cannot simply define a theorem at the top level and the wikipedia page was not supplying a complete initial example. I wrapped the theorem in a theory as follows:
theory Scratch
imports Main
begin
(* Theorem *)
end
Isabelle stopped complaining about the theorem, but, on the second line of the theorem, it now says:
Inner lexical error at: ℚ
Failed to parse proposition
It is also complaining about the proof line:
Illegal application of command "proof" in theory mode
It also has an error for the remaining lines in the theorem.
What is the proper way to wrap this theorem provided by wikipedia so that it can be checked in Isabelle?
I completely agree to Manuel, that just importing Main is not sufficient. If you're not interested in proofs, but just on testing irrationality then a good possibility would be to include $AFP/Real_Impl/Real_Impl from the Archive of Formal Proofs: then testing irrationality becomes very easy:
theory Test
imports "$AFP/Real_Impl/Real_Impl"
begin
lemma "sqrt 2 ∉ ℚ" by eval
lemma "sqrt 1.21 ∈ ℚ" by eval
lemma "sqrt 3.45 ∉ ℚ" by eval
end
Your guess that you have to wrap the “theorem” command in a theory in the way you did is correct. However, you need a few more imports, imports Main does not even load the theories containing sqrt, rational numbers, and prime numbers.
Moreover, the proof on Wikipedia is somewhat outdated. Isabelle is a very dynamic system; its maintainers port all the proofs in the library and the Archive of Formal Proofs with every release, but code snippets lying around somewhere (e.g. Wikipedia) tend to become outdated after a while, and I think this particular one is positively ancient.
For an up-to-date proof of pretty much the same thing, properly embedded in a theory with the right imports, look here:
http://isabelle.in.tum.de/repos/isabelle/file/4546c9fdd8a7/src/HOL/ex/Sqrt.thy
Note that this is for the development version of Isabelle; it may not work with your version. In any case, you should have the same file in the correct version as src/HOL/ex/Sqrt.thy in your downloaded Isabelle distribution.
Probably you encountered some encoding difficulties - this was the problem in my case (I got the same error).
Isabelle uses so called 'Isabelle symbols' to represent unicode characters (see three
(reference manual)[http://isabelle.in.tum.de/doc/isar-ref.pdf] from page 307).
If you use the jEdit IDE that gets distributed with Isabelle 2014 then --> looks the same as the \<longrightarrow> (the Isabelle symbol). The first cannot be parsed, the second is correct. If you copy and pasted the wiki-code this is the reason why it broke.
You can also take a look at the examples in <yourIsabelleInstallFolder/src/HOL/Isar_Examples.thy for further use of the isabelle symbols and the general structure of proofs written in the Isar language.
In Common Lisp, I need to capture user input in the form of a list of reals. This list is terminated by two zeros in a row. For example, 5.0 0 6.0 3 2.0 5 1.0 7 13.0 8 0 0 should return the list (5.0 0 6.0 3 2.0 5 1.0 7 13.0 8).
I've come across the function read-delimited-list, which takes a single character as an ending point. I can stop at a single zero, but I'm not sure how to expand this function, and I don't know of another function that takes a delimited string instead of a char.
EDIT Thanks to the accepted answer, I've developed the following:
(butlast (loop for y = -1 then x for x = (read stream) until (and (= 0 x) (= 0 y))
collect x)))
It seems a bit more readable to me (and at this point I'm openly admiting that my Lisp eyes are only 3 days old), and I'm not sure about performance implications (does collect append or reverse the list after the loop exits scope? is there an easier way to chop off the last element, or simply not append it?).
For such simple case you can just use read in a loop, collect the results read so far and stop, when the last two are zeros.
(defun read-double-zero-terminated-list (stream)
(do* ((prev -1 val)
(val (read stream) (read stream))
list)
((and (zerop prev) (zerop val)) (reverse (cdr list)))
(push val list)))
read-delimited-list is intended for the cases of creating specialized syntax, so it's probably overkill here.
The best way to parse numbers in Common Lisp is to use the library parse-number. If your user input can be read line by line, you can simply split the lines on whitespace and use parse-number on the results.
I'm learning Lisp and have written the following function to collect a list of results.
(defun collect (func args num)
(if (= 0 num)
()
(cons (apply func args)
(collect func args (- num 1)))))
It produced similar output to the built in loop function.
CL-USER> (collect #'random '(5) 10)
(4 0 3 0 1 4 2 1 0 0)
CL-USER> (loop repeat 10 collect (random 5))
(3 3 4 0 3 2 4 0 0 0)
However my collect function blows the stack when I try to generate a list 100,000 elements long
CL-USER> (length (collect #'random '(5) 100000))
Control stack guard page temporarily disabled: proceed with caution
Whereas the loop version doesn't
CL-USER> (length (loop repeat 100000 collect (random 5)))
100000
How can I make my version more space efficient, are there alternatives to consing? I think it's tail recursive. I'm using sbcl. Any help would be great.
No, it is not tail recursive. Neither ANSI Common Lisp says anything about it nor your code:
(defun collect (func args num)
(if (= 0 num)
()
(cons (apply func args)
(collect func args (- num 1)))))
If you look at your code, there is a CONS around your call to COLLECT. This CONS receives the value of the recursive call to COLLECT. So COLLECT can't be tail recursive. It's relatively simple to rewrite your function to something that looks tail recursive by introducing an accumulator variable. The various Lisp or Scheme literature should describe that.
In Common Lisp the default way to program an iterative computation is by using one of the several iterative constructs: DO, DOTIMES, DOLIST, LOOP, MAP, MAPCAR, ...
The Common Lisp standard does not provide tail call optimization (TCO). It would have to be specified what TCO should do in the presence of several other language features. For example dynamic binding and special variables have an effect on TCO. But the Common Lisp standard says simply nothing about TCO in general and about possible effects of TCO. TCO is not a part of the ANSI Common Lisp standard.
Several Common Lisp implementations have a way to enable various tail call optimizations with compiler switches. Note that both the way to enable those and the limitations are implementation specific.
Summary: In Common Lisp use iteration constructs and not recursion.
(defun collect (func args num)
(loop repeat num
collect (apply #'func args)))
Added bonus: it is easier to read.
Common Lisp implementations are not required by the ANSI standard to do tail call optimization; however, most that worth their salt (including SBCL) do optimize.
Your function, on the other hand, is not tail recursive. It can be turned into one by using the common trick of introducing an extra parameter for accumulating the intermediate result:
(defun collect (func args num)
(labels ((frob (n acc)
(if (= 0 n)
acc
(frob (1- n) (cons (apply func args) acc)))))
(frob num nil)))
(The original parameters FUNC and ARGS are eliminated in the local function since they are constant with recpect to it).
Well, the alternative to recursion is iteration.
You should know that Common Lisp does not require tail recursion from its implementors, unlike Scheme.
(defun mycollect (func args num)
(let ((accumulator '())) ; it's a null list.
(loop for i from 1 to num
do
;;destructively cons up the accumulator with the new result + the old accumulator
(setf accumulator
(cons (apply func args) accumulator)))
accumulator)) ; and return the accumulator