I'm looking at the example code in Ch 16 of the book "Clojure Programming" by Emerick, Carper, and Grand, and I see
(ns com.clojurebook.url-shortener
(:use [compojure.core :only (GET PUT POST defroutes)])
(:require (compojure handler route)
[ring.util.response :as response]))
I'm having some trouble mentally parsing the :require clause and would appreciate some help. The first form in the clause, namely (compojure handler route), would appear to be a Prefix List, as recorded in the documentation here. However, it doesn't fit the definition of a prefix list, in that
A prefix list contains the shared prefix followed by libspecs
with the shared prefix removed from the lib names.
But the usage in the book has three symbols, none of which look like a shared prefix. Furthermore,
After removing the
prefix, the names that remain must not contain any periods.
The usage in the book has a remaining name, ring.util.response, with periods in it.
Therefore the term
(:require (compojure handler route)
[ring.util.response :as response])
isn't a prefix list. Then what is it? I can't find a match in the documentation for :require.
Here, you're requiring two things, one of which is a prefix list and the other is a require with options. They are handled independently, which sounds like is where you're getting confused.
The first part (compojure handler route), is a prefix list. The second part [ring.util.response :as response], is a normal libspec, not a prefix list. You can add additional prefix lists and libspecs as needed.
As noted in deterb's answer, the (compojure handler route) is a prefix list - compojure is the common prefix shared by the namespaces to require, and handler and route are the child libspecs. The combining . is implicit.
(:require (compojure handler route))
is equivalent to:
(:require [compojure.handler]
[compojure.route])
You can use symbols as libspecs when there are no additional options, so that could also be written:
(:require compojure.handler
compojure.route)
But when requiring multiple namespaces, I find it more readable to use all vectors rather than a mix of vectors and symbols.
require is also a function in clojure, if you check the source of that function
(defn require[& args]
(apply load-libs :require args))
So, require will take an arbitrary number of libspecs, such as the quoted symbol and vector we’ve just seen. You can also mix and match symbols with vectors. The main thing to remember here is that a libspec should be either a quoted symbol or vector. So whenever you want to use something like :as, that thing (the libspec) should be a vector.
Related
Here's some code I wrote, using clojure.core.match, which performs a pretty common programmng task. A function takes some "commands" (or "objects", "records", or whatever you prefer to call them), has to do something different with each type, and has to destructure them to figure out exactly what to do, and different command types might have to be destructured differently:
(defn action->edits [g action]
"Returns vector of edits needed to perform action in graph g."
(match action
[:boost from to]
[[:add-edge from to 1.0]]
[:retract from to]
[[:remove-edge from to]]
[:normalize from to] ; a change has just been made to from->to
(map (fn [that] [:remove-edge from that])
(successors-except g from to))
[:recip-normalize to from] ; a change has just been made to from->to
[]
[:reduce-to-unofficial from to competitor]
[[:remove-edge from to] (make-competitive-edge from competitor]))
I'm mostly imitating the way people commonly use the pmatch macro in Scheme. I'd like to know what's the idiomatic way to do this in Clojure.
Here's what I like about the above code:
It's very readable.
It was effortless to write.
Here's what I don't like:
Accessing the from and to fields from anywhere but inside a match macro is extremely unreadable and error-prone. For example, to extract the from element from most of the action vectors, you write (action 1). That code will break if I ever add a new action, and it breaks right now on :recip-normalize.
The code generated by match is inefficient: it searches by repeatedly throwing and catching exceptions. It doesn't just generate a big nested if.
I experimented a little with representing the commands as maps, but it seemed to get verbose, and the name of the command doesn't stand out well, greatly reducing readability:
(match action
{:action :boost :from from :to to}
[{:edit :add-edge :from from :to to :weight 1.0}]
{:action :retract :from from :to to}
[{:edit :remove-edge :from from :to to}]
. . .)
Probably future versions of match will generate better code, but the poor code generated now (and lack of support for records) suggests that in Clojure, people have been handling this kind of thing happily for years without match. So how do you do this kind of thing in Clojure?
I would utilize clojure's build-in destructuring facilities, since I do not see a requirement for core.match here - but I might be missing something.
For example:
(defn action->edits [g [action from to]]
(condp = action
:boost "boosting"
:retract "retracting"
:normalize-ksp-style (recur g [:boost from to])
nil))
(action->edits 2 [:normalize-ksp-style 1 2])
;=> "boosting"
In a file I can do this:
(:require [clojurewerkz.neocons.rest :as nr])
how can I import this into the repl and still be able to refer to it by 'nr'?
thanks
Lee's answer is right, of course, but why do you need to quote? The vector [...] is evaluated and the values inside too, and here both clojurewerkz.neocons.rest and nr are treated as variables, which are unbound (you do have an error message, don't you?). You can also choose to quote the symbols:
(require ['clojurewerkz.neocons.rest :as 'nr])
This also means that you could require namespaces dynamically, if you pass a variable.
But then, why don't you need to quote inside a file? I suppose that this is because the (require ... ) found in your file is enclosed in an ns macro, and as such, the forms are not evaluated. See require.
You can use require and quote the vector:
(require '[clojurewerkz.neocons.rest :as nr])
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.
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.
Background
I've written a hack for Emacs that lets me send a Clojure form from an editor buffer to a REPL buffer. It's working fine, except that if the two buffers are in different namespaces the copied text doesn't usually make sense, or, worse, it might make sense but have a different meaning to that in the editor buffer.
I want to transform the text so that it makes sense in the REPL buffer.
A Solution in Common Lisp
In Common Lisp, I could do this using the following function:
;; Common Lisp
(defun translate-text-between-packages (text from-package to-package)
(let* ((*package* from-package)
(form (read-from-string text))
(*package* to-package))
(with-output-to-string (*standard-output*)
(pprint form))))
And a sample use:
;; Common Lisp
(make-package 'editor-package)
(make-package 'repl-package)
(defvar repl-package::a)
(translate-text-between-packages "(+ repl-package::a b)"
(find-package 'editor-package)
(find-package 'repl-package))
;; => "(+ A EDITOR-PACKAGE::B)"
The package name qualifications in the input string and the output string are different—exactly what's needed to solve the problem of copying and pasting text between packages.
(BTW, there's stuff about how to run the translation code in the Common Lisp process and move stuff between the Emacs world and the Common Lisp world, but I'm ok with that and I don't particularly want to get into it here.)
A Non-Solution in Clojure
Here's a direct translation into Clojure:
;; Clojure
(defn translate-text-between-namespaces [text from-ns to-ns]
(let [*ns* from-ns
form (read-string text)
*ns* to-ns]
(with-out-str
(clojure.pprint/pprint form))))
And a sample use:
;; Clojure
(create-ns 'editor-ns)
(create-ns 'repl-ns)
(translate-text-between-namespaces "(+ repl-ns/a b)"
(find-ns 'editor-ns)
(find-ns 'repl-ns))
;; => "(+ repl-ns/a b)"
So the translation function in Clojure has done nothing. That's because symbols and packages/namespaces in Common Lisp and Clojure work differently.
In Common Lisp symbols belong to a package and the determination of a symbol's package happens at read time.
In Clojure, for good reasons, symbols do not belong to a namespace and the determination of a symbol's namespace happens at evaluation time.
Can This Be Done in Clojure?
So, finally, my question: Can I convert Clojure code from one namespace to another?
I don't understand your use case, but here is a way to transform symbols from one namespace to another.
(require 'clojure.walk 'clojure.pprint)
(defn ns-trans-form [ns1 ns2 form]
(clojure.walk/prewalk
(fn [f] (if ((every-pred symbol? #(= (namespace %) ns1)) f)
(symbol ns2 (name f))
f))
form))
(defn ns-trans-text [ns1 ns2 text]
(with-out-str
(->> text
read-string
(ns-trans-form ns1 ns2)
clojure.pprint/pprint)))
(print (ns-trans-text "editor-ns" "repl-ns" "(+ editor-ns/a b)" ))
;=> (+ repl-ns/a b)
So, editor-ns/a was transformed to repl-ns/a.
(Answering my own question...)
Given that it's not easy to refer to a namespace's non-public vars from outside the namespace, there's no simple way to do this.
Perhaps a hack is possible, based on the idea at http://christophermaier.name/blog/2011/04/30/not-so-private-clojure-functions. That would involve walking the form and creating new symbols that resolve to new vars that have the same value as vars referred to in the original form. Perhaps I'll investigate this further sometime, but not right now.