I have a use case where I want to update one of my map type variables inside a method call. To demonstrate here is a code snippet,
(defn func [mymap]
(conj mymap [1 2])) ;update mymap variable here such that changes are persistent after the method returns
(let [mymap {}
_ (func mymap)] (println mymap))
which outputs {} because I think a new map is created with the conj function. How do I update the mymap variable in func such that the output of the above program will be {1 2}?
If it is not possible in Clojure, how are such use cases handled in general?
Many choices. Simplest is to rebind the mymap variable. Consider:
(ns tst.demo.core
(:use tupelo.core tupelo.test))
(defn doit [mymap]
(into mymap {:b 42}))
(dotest
(let [m {:a 1}
m2 (doit m)]
(spyx m2)))
m2 => {:a 1, :b 42}
and we get what we expect.
Update the code to reuse the name m:
(dotest
(let [m {:a 1}
m (doit m)]
(spyx m)))
m => {:a 1, :b 42}
Here the 2nd usage of m creates a separate variable that shadows the first m. This works great and people do it accidentally all the time without even realizing it.
If you want to copy the behavior of Java, you need a Clojure atom to create a mutable storage location.
(dotest
(let [m-atom (atom {:a 1})]
(swap! m-atom doit)
(spyx #m-atom)))
(deref m-atom) => {:a 1, :b 42}
Here swap! applies the function doit to the contents
of m-atom, the puts the results as the new contents.
We need the #m-atom or (deref m-atom) to pull out the contents of the atom for printing.
The above convenience functions can be found here. I also have some great documentation references in this template project. Be especially sure to study the Clojure Cheatsheet daily.
Clojure uses immutable data types by default. This means, you cannot
mutate the data in place like you are used to from many other
programming languages.
The functional approach here is to use the result from the conj (the
last statement inside a defn is it's return value).
(let [mymap {}
result (func mymap)]
(println result))
The longer you can keep up with pure functions on immutable data the
easier your life will be; reasoning about your programs and testing
them becomes a lot easier.
There is of course the option to use mutable data classes from Java, but
don't use them unless you really have to.
And since nearly all programs need some state, there are also atom:s
I only mention this here, because short of def everywhere, atom
everywhere are the next best "trap" beginners run into.
Related
I am new to common lisp. Is there a CL library to pretty print collections, in my case, nested hash tables?
If you considering writing it yourself, here is a starting point using print-object. It is not implementation independent, but this works at least in LispWorks and SBCL.
(defmethod print-object ((object hash-table) stream)
(format stream "#HASH{~{~{(~a : ~a)~}~^ ~}}"
(loop for key being the hash-keys of object
using (hash-value value)
collect (list key value))))
First, CL does not have a "collection" type.
Second, some (most?) CL implementations will print hash tables with content if you set *print-array* to t.
Third, if your CL implementation does not do that, you can easily whip up your own, based on, say, hash-table->alist.
With the Serapeum library, we can use the dict constructor and enable pretty-printing with (toggle-pretty-print-hash-table):
(dict :a 1 :b 2 :c 3)
;; =>
(dict
:A 1
:B 2
:C 3
)
With the Rutils library:
if we enable pretty printing of hash-tables with (toggle-print-hash-table), they are printed like so:
rutils-user> #h(:foo 42)
#{
:FOO 42
}
It uses print-object under the hood, so its warning applies (not standard, but works in some implementations like SBCL).
The #h reader macro is a shortcut to create hash-tables.
I'm looking for a simple way to return a new structure which is a copy of an existing one with some fields changed, without modifying the original.
I get that you can use setf to change the data in one of the fields, like so:
[1]> (defstruct foo bar)
FOO
[1]> (defvar quux (make-foo :bar 12))
QUUX
[1]> (foo-bar quux)
12
[1]> (setf (foo-bar quux) 15)
15
[1]> (foo-bar quux)
15
But as I stated, this essentially destroys the original data, which isn't what I'm going for.
I could of course do something like this:
(defstruct foo bar baz) ; define structure
(defvar quux (make-foo :bar 12 :baz 200)) ; make new instance
(defvar ping (copy-foo quux)) ; copy instance
(setf (foo-bar ping) 15) ; change the bar field in ping
But it seems more like a work-around than anything.
In Erlang you can do something like this:
-record(foo, {bar, baz}). % defines the record
example() ->
Quux = #foo{bar = 12, baz = 200}, % creates an instance of the record
Ping = Quux#foo{bar = 15}. % creates a copy with only bar changed
No data modified.
PS Yes I'm aware that Common Lisp isn't Erlang; but Erlang made it convenient to work with records/structures immutably, and since functional style is encouraged in Common Lisp, it would be nice if there was a similar option available.
Erlang records are similar to Prolog structures. The Prolog I know implements this as a predicate named update_struct/4 which admits a macro expansion: it takes a type parameter and expands into two unifications. The same kind of processing is done in Erlang, according to the documentation. In Common Lisp, we don't need to pass the type explicitly, as shown with the following update-struct function:
(defun update-struct (struct &rest bindings)
(loop
with copy = (copy-structure struct)
for (slot value) on bindings by #'cddr
do (setf (slot-value copy slot) value)
finally (return copy)))
Example
CL-USER> (defstruct foo bar baz)
FOO
CL-USER> (defparameter *first* (make-foo :bar 3))
*FIRST*
CL-USER> (defparameter *second* (update-struct *first* 'baz 2))
*SECOND*
CL-USER> (values *first* *second*)
#S(FOO :BAR 3 :BAZ NIL)
#S(FOO :BAR 3 :BAZ 2)
Specification
Rainer Joswig kindly pointed out that:
There is one thing which is undefined by the standard: using SLOT-VALUE on structure objects is undefined. But it should work on most implementations, as they provide this feature. The only implementation where it does not seem to work is GCL.
Indeed, the HyperSpec says about SLOT-VALUE:
Note in particular that the behavior for conditions and structures is not specified.
An implementation might behave differently if the structured is backed by a list or vector (see the ̀:TYPE option). Anyway, if you need to be portable you'd better use classes.
This topic was also explained in detail by Rainer in common lisp: slot-value for defstruct structures.
Other immutable data-structures
Consider also using property lists, which play nicely with an immutable approach.
Say your initial list x is:
(:a 10 :b 30)
Then (list* :b 0 x) is the following list:
(:b 0 :a 10 :b 30)
... where the most recent value associated with :b shadows the ones after (see GETF).
Loop details
The bindings list is a property list, with alternation of keys and values (like keyword parameters).
In the LOOP expression above, I am iterating over the list of bindings using ON, which means that I am considering each sublist instead of each element. In other words (loop for x on '(a b c d)) successively binds x to (a b c d), (b c d), (c d) and finally (c).
However, since I provide a custom BY argument, the next element is computed using CDDR, instead of the default CDR (so, we advance by two cells instead of by one).
That allows me to consider each pair of key/value elements in the list, and bind them to slot and value thanks to the destructuring syntax.
I'm having trouble returning the values from core.async channels in the browser in the order they were created (as opposed to the order at which they return a value). The channels themselves are returned from mapping cljs-http.client/get over a list of URLs.
If I bind the results manually in a let block then I can return the results in the order of the channels "by hand", but this obviously a problem when I don't know how many channels exist.
(let [response-channels (map #(http/get "http://date.jsontest.com" {:with-credentials? false}) (range 3))]
; Response is now three channels generated by http/get:
;(#object[cljs.core.async.impl.channels.ManyToManyChannel]
; #object[cljs.core.async.impl.channels.ManyToManyChannel]
; #object[cljs.core.async.impl.channels.ManyToManyChannel])
; If I want the results back in the guaranteed order that I made them, I can do this:
(go (let [response1 (<! (nth response-channels 0))
response2 (<! (nth response-channels 1))
response3 (<! (nth response-channels 2))]
(println "This works as expected:" response1 response2 response3))))
But if I try to map <! over the channels instead of binding to them individually then I just get a the list of channels instead of their values.
(let [response-channels (map #(http/get "http://date.jsontest.com" {:with-credentials? false}) (range 3))]
(let [responses (into [] (map (fn [c] (go (<! c))) response-channels))]
(println "This just returns the channels:" responses)
; This is still just a vec of many-to-many channels
; [#object[cljs.core.async.impl.channels.ManyToManyChannel]
; #object[cljs.core.async.impl.channels.ManyToManyChannel]
; #object[cljs.core.async.impl.channels.ManyToManyChannel]]
)
)
I suspect it's a problem with the location of the go block, however I can't move it outside of the anonymous function without an error that I'm using <! outside of a go block.
This doesn't work:
(into [] (go (map <! response-channels)))
And neither does this:
(go (let [responses (into [] (map <! response-channels))]))
I also tried merging the channels via async/merge and then using async/reduce to conjoin the values but results are in the order of when the requests were fulfilled, not the order of the channels being merged.
Can anyone shed some light on retrieving values from a list of channels in the order the channels exist in the list?
In Clojure you could do (map <!! response-channels), but that's not possible in ClojureScript. What's even more important is that it's discouraged to use map—or lazy operations in general—for side effects (checkout this blog post to see why). The reason your code doesn't yield the results you're expecting is the (nested) use of fn within the go block (see this answer):
By [the Clojure go-block] stops translation at function boundaries, I mean this: the go block takes its body and translates it into a state-machine. Each call to <! >! or alts! (and a few others) are considered state machine transitions where the execution of the block can pause. At each of those points the machine is turned into a callback and attached to the channel. When this macro reaches a fn form it stops translating. So you can only make calls to <! from inside a go block, not inside a function inside a code block.
I'm not quite sure, but when you have a look at (source map) you'll see that it invokes fn directely as well as via other functions (such as lazy-seq), which is probably why (go (map <! response-channels)) doesn't work.
Anyway, how about doseq:
(go (doseq [c response-channels]
(println (<! c))))
This will respect the order within response-channels.
I want to generate named functions with fn and return them from the macro, I tried the following example:
(defmacro getfn
[namestr children]
`(fn fn-name# []
(println "Recursing" ~namestr)
(doall (map (fn [child#] (child#)) ~children))))
(def foo (getfn "foo" []))
(def bar (getfn "bar" [foo]))
(defn -main [& args]
(bar))
The resulting output is usually as expected:
Recursing bar
Recursing foo
However, when I run this compiled ahead-of-time (AOT) I get:
Recursing bar
Recursing bar
...
Recursing bar
Recursing bar
Exception in thread "main" java.lang.StackOverflowError
I find it pretty strange that bar keeps calling itself instead of foo, the only sensible reason for this is for the generated symbol fn-name# to leak outside its scope. Is this a bug in Clojure or intended behaviour?
Update: For clarity should mention that removing the fn-name# symbol and making the function anonymous fixes this problem. However, in my actual code I need to call it recursively sometimes, so naming it is necessary.
One solution I have for this problem is to use gensym to get a new symbol for each version of the macro, this would work by modifying the getfn as follows:
(defmacro getfn
[namestr children]
`(let [fn-name# (gensym)]
(fn fn-name# []
(println "Recursing" ~namestr)
(doall (map (fn [child#] (child#)) ~children)))))
This feels a bit unnecessary since by definition the fn name should be relevant only inside its own scope.
Update: Just tested with alpha releases and it seems Clojure 1.7.0-alpha3 and later work without this hack, Clojure 1.7.0-alpha2 and earlier are broken. Using this workaround is probably ok until stable version of 1.7.0 is released, unless someone can think of something better.
I am learning Clojure by solving problems, I'm stuck with one of them, basically I have to find the top five strings in a log file.
Here is what I've got so far:
(ns topfive
(:import (java.io BufferedReader FileReader)))
(defn extract-query [line]
(.substring line (+ (.lastIndexOf line "=") 1) (.lastIndexOf line "]")))
(defn process-file [file-name, queries]
(with-open [rdr (BufferedReader. (FileReader. file-name))]
(doseq [line (line-seq rdr)]
(assoc queries (extract-query line) (inc (get queries (extract-query line) 0))))))
(process-file "in" {})
My problem is that queries does not contain anything, I've already checked that extract-queries returns the string I want, I thought that this might have something to do with the language itself, I've read that Clojure has immutability at language level, but this still does not seem a good point to me.
Could you suggest something about what I am doing wrong?
Clojure does have immutability at a low level, and hash-maps are immutable. So assoc doesn't mutate a map in-place, it creates a new map with an updated item in it, and returns the new map. You're calling assoc over and over, but discarding the results.
One fix is to use reduce instead of doseq. doseq iterates over a seq and does something to each item, but doesn't accumulate any results. So it should be used mostly for things that have side effects, e.g. printing to screen or file. reduce similarly iterates over a seq, but it does accumulate results.
(defn process-file [file-name, queries]
(with-open [rdr (BufferedReader. (FileReader. file-name))]
(reduce (fn [queries, line]
(assoc queries (extract-query line) (inc (get queries (extract-query line) 0))))
queries
(line-seq rdr))))
You could do a few things to simplify this a bit further. There's no need for a queries parameter to process-file, since it's always going to be an empty map to begin with. Your assoc line can be written more concisely using update-in and fnil; this also lets us avoid calling extract-query twice per line. You can replace all the calls to the Java Reader classes with the Clojure wrapper reader in clojure.java.io. You can replace your calls to substring with a regular expression; regex is more concise, but for large inputs your version might perform faster. You could also replace the anonymous function in my example with a sugary reader macro version using #(), though it's starting to look a bit noisy at this point, so I'd probably use let to make it read a bit better.
(ns topfive
(:require [clojure.java [io :as io]]))
(defn extract-query [line]
(nth (re-find #"query=([^]]+)" line) 1))
(defn process-file [file-name]
(with-open [rdr (io/reader file-name)]
(reduce #(let [search-term (extract-query %2)]
(update-in %1 [search-term] (fnil inc 0)))
{}
(line-seq rdr))))
in addition to Brians excellent answer: The threading macro may improve readability:
(ns stackoverflow
(:use [clojure.string :only [split]]
[clojure.java.io :only [reader]]))
(->> (reader "input.txt")
(line-seq)
(map #(last (split % #"=")))
(frequencies))