Recover map from the string representation - clojure

I have a string which is a representation of a clojure map. Is there an easy way to reconstruct the map from the string?
An example of the string -
{:Location {:CountryData {:country_cf 99, :country_code "us", :country "united states"}, :longitude -80.17833, :msa 33100, :dma 528}

Use read-string function:
(read-string "{:Location {:CountryData {:country_cf 99, :country_code \"us\", :country \"united states\"}, :longitude -80.17833, :msa 33100, :dma 528}}")

Very interesting. I've never used clojure, but in Lisp dialects this is done with the read function. I'll go out on a limb here and say you can do it in clojure according to http://clojure.org/reader.
So maybe (with-in-str your-string (read))?

Related

What data structure to use for implementing a library management system

I'm new to functional programming and am currently at the end of "Getting Clojure" book. Since most of the examples in the book refer to books/library management, i thought of implementing a library management system as a project to help me learn and clear the concepts. I would like some advise on what would be the best data structure to hold the library - I'm thinking of either a vector of book maps or a map of book maps. Maps are easy to lookup. Vectors can be accessed quickly as well. I'm thinking of
{:ISBN {:title "Book title" :edition 1 :publisher "ABC publishing"}}
this way the lookup will be on ISBN number, but i would also like to lookup using book title ..but not sure how. Any help, suggestions, advise would be greatly appreciated.
You can use the index function in clojure.set:
(require '[clojure.set :as set])
(def library #{{:title "Book title" :edition 1 :publisher "ABC publishing" :isbn "1234"}
{:title "A title" :edition 2 :publisher "123 publishing" :isbn "4321"}})
(def by-isbn (set/index library [:isbn]))
(by-isbn {:isbn "1234"})
;; => #{{:title "Book title", :edition 1, :publisher "ABC publishing", :isbn "1234"}}
(def by-title (set/index library [:title]))
(by-title {:title "A title"})
;; => #{{:title "A title", :edition 2, :publisher "123 publishing", :isbn "4321"}}
In java you can use a data structure called Trie. it is better than Hashmaps and the time complexity of operations are O(1).
In this DS we can reuse the words like if we already have the word 'new' and you want to add another word 'news' It will it will just use the existing word new to make a new word. which stores storage.

Meaning of # in clojure

In clojure you can create anonymous functions using #
eg
#(+ % 1)
is a function that takes in a parameter and adds 1 to it.
But we also have to use # for regex
eg
(clojure.string/split "hi, buddy" #",")
Are these two # related?
There are also sets #{}, fully qualified class name constructors #my.klass_or_type_or_record[:a :b :c], instants #inst "yyyy-mm-ddThh:mm:ss.fff+hh:mm" and some others.
They are related in a sence that in these cases # starts a sequence recognisible by clojure reader, which dispatches every such instance to an appropriate reader.There's a guide that expands on this.
I think this convention exists to reduce the number of different syntaxes to just one and thus simplify the reader.
The two uses have no (direct) relationship.
In Clojure, when you see the # symbol, it is a giant clue that you are "talking" to the Clojure Reader, not to the Clojure Compiler. See the full docs on the Reader here: https://clojure.org/reference/reader.
The Reader is responsible for converting plain text from a source file into a collection of data structures. For example, comparing Clojure to Java we have
; Clojure ; Java
"Hello" => new String( "Hello" )
and
[ "Goodbye" "cruel" "world!" ] ; Clojure vector of 3 strings
; Java ArrayList of 3 strings
var msg = new ArrayList<String>();
msg.add( "Goodbye" );
msg.add( "cruel" );
msg.add( "world!" );
Similarly, there are shortcuts that the Reader recognizes even within Clojure source code (before the compiler converts it to Java bytecode), just to save you some typing. These "Reader Macros" get converted from your "short form" source code into "standard Clojure" even before the Clojure compiler gets started. For example:
#my-atom => (deref my-atom) ; not using `#`
#'map => (var map)
#{ 1 2 3 } => (hash-set 1 2 3)
#_(launch-missiles 12.3 45.6) => `` ; i.e. "nothing"
#(+ 1 %) => (fn [x] (+ 1 x))
and so on. As the # or deref operator shows, not all Reader Macros use the # (hash/pound/octothorpe) symbol. Note that, even in the case of a vector literal:
[ "Goodbye" "cruel" "world!" ]
the Reader creates a result as if you had typed:
(vector "Goodbye" "cruel" "world!" )
Are these two # related?
No, they aren't. The # literal is used in different ways. Some of them you've already mentioned: these are an anonymous function and a regex pattern. Here are some more cases:
Prepending an expression with #_ just wipes it from the compiler as it has never been written. For example: #_(/ 0 0) will be ignored on reader level so none of the exception will appear.
Tagging primitives to coerce them to complex types, for example #inst "2019-03-09" will produce an instance of java.util.Date class. There are also #uuid and other built-in tags. You may register your own ones.
Tagging ordinary maps to coerce them to types maps, e.g. #project.models/User {:name "John" :age 42} will produce a map declared as (defrecord User ...).
Other Lisps have proper programmable readers, and consequently read macros. Clojure doesn't really have a programmable reader - users cannot easily add new read macros - but the Clojure system does internally use read macros. The # read macro is the dispatch macro, the character following the # being a key into a further read macro table.
So yes, the # does mean something; but it's so deep and geeky that you do not really need to know this.

Reasons not to use use a wildcard pull?

Are there any reasons not to use a wildcard pull?
(defn pull-wild
"Pulls all attributes of a single entity."
[db ent-id]
(d/pull db '[*] ent-id))
It's much more convenient than explicitly stating the attributes.
It depends on which attributes you need to have in your application and if it's data intensive or whether you want to pull lots of entities.
In case you use the client-library, you might want to minimize the data that needs to be send over the wire.
I guess there are lots of other thoughts about that.
But as long as it's fast enough I would pull the wildcard.
fricke
You may also be interested in the entity-map function from Tupelo Datomic. Given an EID (or a Lookup Ref) it will return the full record as a regular Clojure map:
(let [
; Retrieve James' attr-val pairs as a map. An entity can be referenced either by EID or by a
; LookupRef, which is a unique attribute-value pair expressed as a vector.
james-map (td/entity-map (live-db) james-eid) ; lookup by EID
james-map2 (td/entity-map (live-db) [:person/name "James Bond"] ) ; lookup by LookupRef
]
(is (= james-map james-map2
{:person/name "James Bond" :location "London" :weapon/type #{:weapon/wit :weapon/gun} } ))

Tracing functions when the arguments are big maps

When I trace a function, if one of the arguments is a nested map with a lot of elements, the trace is filled with clutter. Here's a typical example:
TRACE t36705: (get-value {:nodeclass :simple, :nodeid :simple25, :dock {:constan
t-dock {:name :constant-dock, :value 22, :dockclass {:name :constant-dock, :link
-policy {:lp-committed? #object[fargish.links$fn__5756 0x407956a5 "fargish.links
$fn__5756#407956a5"], :lp-reciprocate-no-commitment #object[clojure.core$constan
tly$fn__4614 0x69497a36 "clojure.core$constantly$fn__4614#69497a36"], :lp-recipr
ocate-commitment #object[clojure.core$constantly$fn__4614 0x30ee413a "clojure.co
re$constantly$fn__4614#30ee413a"], :lp-can-boost-to #object[fargish.links$fn__57
58 0x5df17e60 "fargish.links$fn__5758#5df17e60"], :lp-official-partners #object[
fargish.links$fn__5760 0x3df2f4ab "fargish.links$fn__5760#3df2f4ab"], :lp-normal
ize-after-add #object[clojure.core$constantly$fn__4614 0x386cc1c4 "clojure.core$
constantly$fn__4614#386cc1c4"], :lp-reduce-to-uncommitted #object[fargish.links$
fn__5765 0x7bd4f212 "fargish.links$fn__5765#7bd4f212"], :lp-committed-to #object
[fargish.links$fn__5767 0x5c3cc103 "fargish.links$fn__5767#5c3cc103"], :lp-boost
#object[fargish.links$fn__5771 0x423e35f0 "fargish.links$fn__5771#423e35f0"]},
:maker #object[fargish.spec_test$eval36501$__GT_Dock_constant_dock__36515 0x19cc
229b "fargish.spec_test$eval36501$__GT_Dock_constant_dock__36515#19cc229b"]}}, :
function-dock {:name :function-dock, :value #fargish.spec.Vfunc{:args (constant-
dock), :f #object[fargish.spec_test$fn__36544 0x135647d3 "fargish.spec_test$fn__
36544#135647d3"]}, :dockclass {:name :function-dock, :link-policy {:lp-committed
? #object[fargish.links$fn__5756 0x407956a5 "fargish.links$fn__5756#407956a5"],
:lp-reciprocate-no-commitment #object[clojure.core$constantly$fn__4614 0x69497a3
6 "clojure.core$constantly$fn__4614#69497a36"], :lp-reciprocate-commitment #obje
ct[clojure.core$constantly$fn__4614 0x30ee413a "clojure.core$constantly$fn__4614
#30ee413a"], :lp-can-boost-to #object[fargish.links$fn__5758 0x5df17e60 "fargish
.links$fn__5758#5df17e60"], :lp-official-partners #object[fargish.links$fn__5760
0x3df2f4ab "fargish.links$fn__5760#3df2f4ab"], :lp-normalize-after-add #object[
clojure.core$constantly$fn__4614 0x386cc1c4 "clojure.core$constantly$fn__4614#38
6cc1c4"], :lp-reduce-to-uncommitted #object[fargish.links$fn__5765 0x7bd4f212 "f
argish.links$fn__5765#7bd4f212"], :lp-committed-to #object[fargish.links$fn__576
7 0x5c3cc103 "fargish.links$fn__5767#5c3cc103"], :lp-boost #object[fargish.links
$fn__5771 0x423e35f0 "fargish.links$fn__5771#423e35f0"]}, :maker #object[fargish
.spec_test$eval36523$__GT_Dock_function_dock__36537 0x34584446 "fargish.spec_tes
t$eval36523$__GT_Dock_function_dock__36537#34584446"]}}}} constant-dock)
TRACE t36705: => nil
What's a technique for setting things up so these traces print out without so much clutter? I don't expect traces to be super-easy to read, but there has to be a better way than this.
Unfortunately, clojure.tools.trace doesn't allow customizing the output of trace logs. I wasn't sure if you could modify your source code between runs or you needed a mechanism to plugin into a running system where you cannot modify function implementation.
From your comment it seems you can modify a function you want to trace. Based on your requirement to log only a subset of function's arguments content I would switch to ordinary logging (either with println or with some logging framework) and add explicit logging expressions to log only relevant data.
For example:
(defn some-function
[a b]
(println "some-function" {:a (select-keys a [:x :y]) :b (select-keys b [:x :z])})
(comment your function body))
It's not that easy as changing defn to deftrace but can be customized any way you want.

replace escaped unicode with elisp

By calling google dictionary api in emacs,
http://www.google.com/dictionary/json?callback=cb&q=word&sl=en&tl=en&restrict=pr%%2Cde&client=te
I can get response like below
"entries": [{
"type": "example",
"terms": [{
"type": "text",
"text": "his grandfather\x27s \x3cem\x3ewords\x3c/em\x3e had been meant kindly",
"language": "en"
}]
}]
As you can see there are escaped unicode in "text". I want to convert them in function like below.
(defun unescape-string (string)
"Return unescape unicode string"
...
)
(unescape-string "his grandfather\x27s \x3cem\x3ewords\x3c/em\x3e")
=> "his grandfathers's <em>words</em>"
(insert #x27)'
(insert #x27)'
(insert #x3c)<
(insert #x3e)>
Here's what I tried
replace-regexp-in-string
custom replace like http://www.emacswiki.org/emacs/ElispCookbook#toc33
But, I think I don't know how to replace '\x123' with corresponding unicode into buffer or string.
Thanks in advance
Seems like the simplest way to do it:
(read (princ "\"his grandfather\\x27s \\x3cem\\x3ewords\\x3c/em\\x3e had been meant kindly\""))
;; "his grandfather's ώm>words</em> had been meant kindly"
Also it is really interesting that Emacs parses \x3ce rather then \x3c. I'm not sure if this is a bug or intended behaviour. I always thought it's not supposed to read more then two characters after x...
If you still wanted to use read + princ combination, you'd need to put a backslash to prevent Emacs from parsing more characters, like so: \x3c\e. Or here's something quick I could come up with:
(defun replace-c-escape-codes (input)
(replace-regexp-in-string
"\\\\x[[:xdigit:]][[:xdigit:]]"
(lambda (match)
(make-string 1 (string-to-number (substring match 2) 16)))
input))
(replace-c-escape-codes "his grandfather\\x27s \\x3cem\\x3ewords\\x3c/em\\x3e")
"his grandfather's <em>words</em>"