CLOJURE
Hi everyone, I am new to clojure. I would like to update my record with a split string.
(defrecord Learning [Name Age Gender])
(def person [:Name :Age :Gender])
(let person
(clojure.string/split "John,12,Male" #","))
I am able to split the string but it throws an exception
IllegalArgumentException let requires a vector for its binding in ShipDataRecord:1 clojure.core/let (core.clj:3965)
Can Someone kindly explain how should I go about doing it?
Looks like you missed a lot.
First, you using def the wrong way. All variables in clojure are immutable. So, after you defined some variable you can't change its value, but you can rebind it with a new value in any local context using let.
Second, your using of let is incorrect. Try to read Clojure Docs:
(let [x 1]
x)
let creates new context by binding some variables with new values. [x 1] means that you bind value 1 to the variable x. But outside of let x won't change.
What you want to do is:
(defrecord Learning [Name Age Gender])
(def person
(apply ->Learning
(clojure.string/split "John,12,Male" #",")))
Related
If I have an hash-map and I want to assoc a value to it, and I get the key as an argument, what should i do?
(defn define [name type kind] "define new var in one of the tables"
(if (or (= type "static") (= type "field"))
(def classScope (assoc classScope name (list type kind (addCount kind))))
(def methodScope (assoc methodScope name (list type kind (addCount kind))))
)
)
My problem is that i can't use :name, and not 'name.
Thanks!!
Update: If you want your keys to be in keyword form, just call keyword on them....
(defn my-map-fn [name type kind]
(assoc some-map (keyword name) (some-fn type kind)))
e.g.
(my-map-fn "some-name" "some-type" "some-kind") => {:some-name some-val}
Note that you shouldn't use def inside of defn. It looks like you want to keep a map of data and as you call define you want to store some more data in that map. A way that I go about this is to use atoms (there are other ways too).
(defonce classScope (atom {})
(defonce methodScope (atom {}))
(defn define
"if you want a doc string it goes here"
[name type kind]
(swap! (if (#{"static" "field"} type) classScope methodScope)
#(assoc % name (list type kind (addCount kind)))))
the benefit here is you get atomic updates and calls to define that may happen really close together won't butt heads.
Let's start with your explanatory comment:
I'm trying to create an hash-map that's like a symbol table: I will
identify each variable by its name, and it will have a list with its
type, kind and index in the code.
A few thoughts:
Don't use a list for the variable's characteristics; use a map.
You can think of the name of a variable as
a plain old string
a symbol
a keyword
Any of these works as the key of a map entry. Keep it simple. Use a string.
You're going to need such a table for every scope. And a scope should know its enclosing scope.
The descriptors static and field are not types; nor are they
alternatives in - say - Java.
I suggest you look at clojure.spec and typed Clojure to see how similar problems are handled within Clojure.
I declared a map in clojure using
(def finalMap {})
I am appending values to it inside a function using assoc but they are not appending, the map is remaining empty. I think it is due to immutability, can I in some way make a global map mutable.The function is a recursive one and I am appending values each time the function is called.
(defn func [arg1 arg2]
;(map append inside let)
(dorun (for [i (range 0 index)]
(do
(func(arg1 arg2))))))
Can you help me with the correct way to do this?
If you want a mutable map then you should create an atom:
(def final-map (atom {}))
Also normally you would use assoc to add more key value pairs to it. However you will need to use swap! just to be able to call assoc:
(swap! final-map assoc :a "a value")
This will add a key/value pair where the key is the keyword :a and the value is the String "a value".
It might be good to view some other examples of using assoc. Realise that in the code above assoc is being called with the old value of final-map as its first argument, and returning the new value of final-map.
I want to get following results when I evaluate edit-url and (edit-url 1).
edit-url --> "/articles/:id/edit"
(edit-url 1) --> "/articles/1/edit"
Is it possible to define such a Var or something?
Now, I use following function, but I don't want to write (edit-url) to get const string.
(defn edit-url
([] "/articles/:id/edit")
([id] (str "/articles/" id "/edit")))
Thanks in advance.
If those behaviors are exactly what you want, print-method and tagged literals may be used to imitate them.
(defrecord Path [path]
clojure.lang.IFn
(invoke [this n]
(clojure.string/replace path ":id" (str n))))
(defmethod print-method Path [o ^java.io.Writer w]
(.write w (str "#path\"" (:path o) "\"")))
(set! *data-readers* (assoc *data-readers* 'path ->Path))
(comment
user=> (def p #path"/articles/:id/edit")
#'user/p
user=> p
#path"/articles/:id/edit"
user=> (p 1)
"/articles/1/edit"
user=>
)
edit-url will either have the value of an immutable string or function. Not both.
The problem will fade when you write a function with better abstraction that takes a string and a map of keywords to replace with words. It should work like this
(generate-url "/articles/:id/edit" {:id 1})
Clojure is a "Lisp 1" which means that is has a single namespace for all symbols, including both data scalars and functions. What you have written shows the functionally of both a string and a function but for a single name, which you can do in Common Lisp but not Clojure (not that a "Lisp 2" has its own inconveniences as well).
In general this type of "problem" is a non issue if you organize your vars better. Why not just make edit-url a function with variable arity? Without arguments it returns something, with arguments it returns something else. Really the possibilities are endless, even more so when you consider making a macro instead of a function (not that I'm advocating that).
I am trying to rewrite the neo4j sample code located here in clojure. But when I try to create a node, I get the following error
ClassCastException Cannot cast org.neo4j.graphdb.DynamicLabel to [Lorg.neo4j.graphdb.Label; java.lang.Class.cast (Class.java:3094)
Here is my code:
(ns neotest.handler
(:import (org.neo4j.graphdb
DynamicLabel
GraphDatabaseService
Label
Node
ResourceIterator
Transaction
factory.GraphDatabaseFactory
schema.IndexDefinition
schema.Schema)))
(def db
(let [path "C:\\Users\\xxx\\code\\neotest\\resources\\db1"]
(. (new GraphDatabaseFactory) (newEmbeddedDatabase path))))
(defn create-node []
(try (let [tx (. db beginTx)
l (. DynamicLabel (label "User"))]
(. db (createNode l))
(. tx success))))
I have tried type-hinting of all kinds and in all places, and I still get the same error.
It's because of the varargs Label... parameter. This was a bit of Clojure/Java interop I didn't know about: you have to pass the parameter in as an array (even if there's only one), so you need to do something like:
(. db (createNode (into-array Label [l])))
to make it work. There's another afternoon I won't be getting back!
the calls to dynamicLabel in the example java code look like:
DynamicLabel.label( "User" )
which would translate to:
(DynamicLabel/label "user")
because label is a static method of the class org.neo4j.graphdb.DynamicLabel which has the signature:
static Label label(String labelName)
Iam new to clojure and need some help to get a value out of a lazy sequence.
You can have a look at my full data structure here: http://pastebin.com/ynLJaLaP
What I need is the content of the title:
{: _content AlbumTitel2}
I managed to get a list of all _content values:
(def albumtitle (map #(str (get % :title)) photosets))
(println albumtitle)
and the result is:
({:_content AlbumTitel2} {:_content test} {:_content AlbumTitel} {:_content album123} {:_content speciale} {:_content neues B5 Album} {:_content Album Nr 2})
But how can I get the value of every :_content?
Any help would be appreciated!
Thanks!
You could simply do this
(map (comp :_content :title) photosets)
Keywords work as functions, so the composition with comp will first retrieve the :title value of each photoset and then further retrieve the :_content value of that value.
Alternatively this could be written as
(map #(get-in % [:title :_content]) photosets)
A semi alternative solution is to do
(->> data
(map :title)
(map :_content))
This take advances of the fact that keywords are functions and the so called thread last macro. What it does is injecting the result of the first expression in as the last argument of the second etc..
The above code gets converted to
(map :_content (map :title data))
Clearly not as readable, and not easy to expand later either.
PS I asume something went wrong when the data was pasted to the web, because:
{: _content AlbumTitel2}
Is not Clojure syntax, this however is:
{:_content "AlbumTitel2"}
No the whitespace after :, and "" around text. Just in case you might want to paste some Clojure some other time.