First of all you should not nest your functions definitions in another defn
(-main
in this case). defn
or def
always defines symbol bindings at the top level of namespace and they don't nest. If you want to define a locally scoped function you need to use let
and fn
, e.g.
(let [my-fn (fn [a b] (+ a b))]
(my-fn 1 2))
In your particular case I think it would be easier to split your code into multiple functions. This way it will be more readable.
Prompting for a file name is one piece of your logic.
(defn get-existing-filename []
(let [filename (read-line)]
(if (.exists (java.io.File. filename))
filename
(do
(println "Sorry, this file doesn't exists. Type a valid file name...")
(recur)))))
Then you can use it to read a file removing empty lines:
(with-open [input (clojure.java.io/reader (get-existing-filename))]
(->> (line-seq input)
(remove empty?)
(doall)))
For a file with following content:
AAA
BBB
CCC
DDD
it will return
("AAA" "BBB" "CCC" "DDD")
If you really want it as a single function, the following will work:
(defn read-file []
(let [filename (read-line)]
(if (.exists (java.io.File. filename))
(with-open [input (clojure.java.io/reader (get-existing-filename))]
(->> (line-seq input)
(remove empty?)
(doall)))
(do
(println "Sorry, this file doesn't exists. Type a valid file name...")
(recur)))))
Finally, this function can be called from -main
.
I have also noticed another issue in your sample code:
((println "Sorry, this file doesn't exists. Type a valid file name...")
(recur))
if
and if-not
require a single expression for their then
and else
branches. If you want to have multiple expressions you need to nest them in do
:
(do
(println "Sorry, this file doesn't exists. Type a valid file name...")
(recur))
If you need if
or if-not
without the else branch then you can use when
or when-not
macros. Then you don't need to wrap multiple expressions because when
/when-not
will wrap them for your inside of do
.
(when true
(println 1)
(println 2))
is equivalent to
(if true
(do
(println 1)
(println 2)))
(concat list '(line))
is supposed to do, since it's inside of adoseq
.concat
cannot modifylist
; instead, it returns a new piece of data, which is the concatenation of its arguments. – Mars'(line)
will return a list containing a single element, the symbolline
, but what you wanted was the contents of that symbol. What should have been there wasline
without the parentheses or the quote. – Mars(list)
in the last line looks like it returns is the result of calling the functionlist
on no arguments, returning the empty list. When there is an unquoted list, its first argument is normally treated as the name of a function, which is to be evaluated with the other elements of the list as its arguments (except in special cases, as when the list is quoted). However, in this case, you have redefinedlist
, so that it no longer refers to a function. So(list)
will produce an error rather than executing the function thatlist
normally names. – Mars