What's the difference between use and :use in the ns macro - clojure

What's the difference between use and :use in the ns macro?
Docs says the following:
Use :use in the ns macro in preference to calling this directly

It is a bit confusing.
In the ns form, you want to use the keyword version (:require ...) like:
(ns clj.core
(:require [tupelo.core :as t] ))
You should consider this the "normal" way of doing things.
The other version, without the colon, is a function of the same name that can be called at the REPL in case you can't or don't want to use the ns form. This would look like:
> lein repl
user=> (require '[tupelo.core :as t] )
nil
user=> (t/append [1 2 3] 4)
[1 2 3 4]
Please note: For the repl/function version, you must also quote the vector containing the namespace specs. Notice that we did not quote the spec in the ns version using :require.
As an alternative, if you are already in the editor and just want to test something quick at the REPL, you can cut/paste the whole ns form from the top of your file into the REPL:
> lein repl
user=> (ns clj.core
#_=> (:require [tupelo.core :as t] ))
user=>
which is easier and less error-prone than typing the function-version by hand.
For a good overview please see the recent blog posting here: https://stuartsierra.com/2016/clojure-how-to-ns.html

Related

copying the entire contents of a directory recursively using clojure

I wish to emulate cp -R using clojure. Is there an idiomatic way of writing this function so that the entire contents of a directory is recursively copied?
(given there's still interest in this answer):
One can use java java.io.File with clojure's file-seq:
(require '[clojure.java.io :as io])
(->> "/path"
(io/file)
(file-seq)
(run! (your-fn-that-copies-files-and-creates-folders)))
file-seq will return a tree-like structure for your files/folders.
In order to keep a consistent directory structure from your root point onwards, we must take an absolute path and turn it into a relative path:
(require '[clojure.string :as str]
'[clojure.data :as data])
(defn- path->chunks [file] (str/split (.getAbsolutePath file) #"/"))
(defn path->relative [root file]
(str/join "/" (filter some? (second (data/diff (path->chunks root)
(path->chunks file))))))
You can combine all that to perform your recursive copy.

Can't find clojure.set in ClojureClr

I am using ClojureClr 1.6.0 and I'm trying to use clojure.set but I can't find it:
user=> (doc clojure.set/union)
; nil
When I try to use it, I get:
user=> (clojure.set/union #{1 2} #{3})
; TypeNotFoundException Unable to find type: clojure.set clojure.lang.RT.classForNameE (:0)
I tried to load it
user=> (require '(clojure.set))
; nil
but still couldn't find it.
Your syntax for loading the required dependencies appears to be incorrect. I have 1.5.x, not 1.6, but both (require 'clojure.set) (note absence of parentheses around clojure.set) and (require '[clojure.set :as cs]) (give it an alias) work for me. See also Clojure : loading dependencies at the REPL

core.typed + datomic = No reader function for tag id

I'm just getting started with clojure and core.typed, and keep running into the following error when I evaluate (check-ns 'stocks.db) with the following code:
(ns stocks.db
(:gen-class)
(:require [clojure.core.typed :refer [ann HMap]]))
(use '[datomic.api :only [q db] :as d])
(ann break-me [String -> (HMap)])
(defn break-me
"Do I break cored.typed?"
[]
{:db/id #db/id[:db.part/db]})
ExceptionInfo No reader function for tag id clojure.core/ex-info (core.clj:4327)
(break-me) evaluates to {:db/id #db/id[:db.part/db -1000000]} as you'd expect.
Similarly to this unanswered question, the offending term is definitely #db/id.
Thanks for any help.
I'm new to Clojure and Datomic but, I think you need to generate your temporary id with the tempid function that's part of the Datomic API (see http://docs.datomic.com/clojure/index.html#datomic.api/tempid).
So it'd look like this:
(ns stocks.db
(:gen-class)
(:require [clojure.core.typed :refer [ann HMap]]))
(use '[datomic.api :only [q db] :as d])
(ann break-me [String -> (HMap)])
(defn break-me
"Do I break cored.typed?"
[]
{:db/id (tempid :db.part/db)})
I'm having similar issues with clojure.edn/read-string, I haven't quite figured it out. Hope that works for you.
UPDATE:
In this code: https://github.com/Datomic/codeq/blob/master/src/datomic/codeq/core.clj the Datomic folks seem to be doing just what you are. So while in your case I think using tempid will work, I think there's a deeper issue, and it seems like it has to do with the literal #db/id.
UPDATE:
Here: https://github.com/Datomic/day-of-datomic/blob/master/samples/literals_vs_code.clj using tempid rather than literals is recommended.
UPDATE:
I've found a solution that also resolves my issue. I was trying to read in my schema from a file: schema.edn using clojure.edn/read-string after reading the contents as a string using clojure.core/slurp and got similar error complaining about the #db/id literal.
I implemented the read-all and transact-all functions found here: https://github.com/Datomic/day-of-datomic/blob/053b3bd983d165b8fa7c0c039712fb1cb75eddf3/src/datomic/samples/io.clj and it works fine. It seems like there are some sneaky issues with using the reader to parse #db/id literals, still haven't figured out exactly why.
UPDATE:
This is using a Clojure feature called "tagged literals" which allows you to define a map of "data readers" in a file named data_readers.clj at the root of your classpath that should contain a map of tag names and vars that will parse the arguments to the tag.
So with this data_readers.clj file:
{minutes my.project/to-minutes
seconds my.project/to-seconds}
You can do this:
#minutes 3
#seconds 4
You can read about tagged literals at the bottom of this page: http://clojure.org/reader.
However, I still have not figured out the reason for the issue with the #db/id tagged literal. I've posted a question on the Clojure group forum here: https://groups.google.com/forum/#!topic/datomic/Fi7iXps2npw. Update: Ben Kamphaus provides a nice explanation there.

lib names inside prefix lists must not contain periods

I am learning clojure now, I wrote a file like this:
;; File ./mycode/myvoc.clj
(ns mycode.myvoc
(:use 'clojure.java.io)
(:import (java.io.File)))
; more code here...
this file resides in ./mycode/, when I run REPL, I wanna use the function in myvoc.clj, like this:
user=> (use 'mycode.myvoc)
java.lang.Exception: lib names inside prefix lists must not contain periods (myv
oc.clj:1)
I don't know why. if I change myvoc.clj as :
(ns mycode.myvoc)
; (:use 'clojure.java.io)
; (:import (java.io.File)))
It'll be ok but just report no "reader in this context" for I commented the import part.
Could somebody fix this? I alse use require but get the same kind of error.
You need to remove the quote from your :use clause:
(ns mycode.myvoc
(:use clojure.java.io) ; note no '
(:import java.io.File)) ; extra parens removed here; they do no harm,
; though
'clojure.java.io is shorthand for (quote clojure.java.io), so your original :use clause was
(:use (quote clojure.java.io))
This looks as if you were trying to :use a namespace with a prefix of quote and final segment clojure.java.io. The dots in the latter are the direct cause of the error from the point of view of ns.
Incidentally, it's much more usual to (:require [clojure.java.io :as io]) and then say io/file, io/reader etc. than it is to pull in the entire namespace.
Finally, just to be clear, the quote is necessary when using the function use (like in your (use 'mycode.myvoc) call), as opposed to a :use clause in a ns declaration.

How do I use Zip in Clojure?

I am very very new to clojure. The zip utility looks interesting but I cant seem to use it.
I tried
;; ZIP
(:use "zip")
(def data '[[a * b] + [c * d]])
(def dz (zip/vector-zip data))
But I am getting
java.lang.Exception: No such namespace: zip
How do yo use external libraries?
You may be confusing two different ways to import code. You can do it this way:
user> (use 'clojure.zip)
Or while you're declaring a namespace in a source file:
(ns foo
(:use clojure.zip))
The second version is a macro that is expanded into the first.
Outside of (ns), doing (:use "zip") is going to treat :use as a function and call it with "zip" as its parameter (i.e. try to use the string "zip" as a collection and look up the key :use in it), which does nothing.
clojure.zip has some functions whose names clash with things in clojure.core though, so you either have to do something like this:
user> (use '(clojure [zip :rename {next next-zip replace replace-zip remove remove-zip}]))
Or preferably this:
user> (require '(clojure [zip :as zip]))
With the latter you can refer to functions like (zip/vector-zip data) as you wish.
See the documentation for require and refer and the page talking about libs.
I don't know much about clojure, but this little ditty seems to work:
(require '[clojure.zip :as zip])
(def t '(:a (:b :d) (:c :e :f)))
(def z (zip/zipper rest rest cons t))
(zip/node z)