This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2017-02-10
Channels
- # ai (2)
- # beginners (3)
- # boot (113)
- # bristol-clojurians (2)
- # cider (77)
- # clara (43)
- # cljs-dev (48)
- # cljsrn (9)
- # clojure (319)
- # clojure-austin (2)
- # clojure-czech (4)
- # clojure-denmark (4)
- # clojure-france (4)
- # clojure-italy (4)
- # clojure-russia (2)
- # clojure-serbia (10)
- # clojure-spec (79)
- # clojure-uk (64)
- # clojurescript (109)
- # clr (3)
- # conf-proposals (21)
- # core-async (19)
- # cursive (26)
- # datascript (11)
- # datomic (19)
- # devcards (1)
- # emacs (25)
- # figwheel (9)
- # hoplon (31)
- # jobs (7)
- # jobs-discuss (14)
- # leiningen (10)
- # lumo (11)
- # off-topic (37)
- # om (40)
- # onyx (4)
- # perun (8)
- # planck (3)
- # rdf (4)
- # re-frame (40)
- # ring (11)
- # ring-swagger (2)
- # rum (21)
- # spacemacs (2)
- # specter (50)
- # untangled (93)
- # yada (13)
https://clojure.org/reference/protocols <-- see section "extend"
I mean, this looks like a function that takes any arbitrary function, and returns another anonymous function, that has some state in the form of an atom
without trickery, no
although most people would recommend not writing fib as a recursive function in the first place
specifically in line 13, when function 'f' is applied, I wanted to know if the recursive calls are also memoized
no, they will not be
those internal calls will be calling the original function
memoization is tricky to use with recursive functions
but again, most people would suggest trying to avoid recursive functions
you can write fib as a tail-recursive loop/recur instead
then memoizing it is fine
okay that makes a lot of sense @alexmiller! got it, I'm not going to use this in production - just for educational purposes đ
if you google for it, there are a large number of fib variants out there in Clojure
okay - another quick question - if I repeatedly call the same function - how is the original function f not invoked again? How does the atom persist across multiple function calls?
if you notice there is a let
around the creation of the fn
and I invoke (mfoo bar) multiple times, how does the second function call access that cache?
the fn
closes over the local binding mem
so the function itself contains a reference to the atom
itâs a stateful function
so for somebody coming from Object oriented languages - atom is like a global variable?
kind of in effect here, but not really
whatâs actually happening under the hood is that when you create a fn it creates a Java class
that class has a field that corresponds to mem
the instance of the class that you get back has the mem
field populated with an instance of an atom
that field is not publicly accessible - itâs a private field of the function class
to âuseâ it, you have to invoke the function which controls access to it
okay - makes sense. It's a kind of a global but only visible from within the function, kind of like class static
yeah, but itâs not static, itâs a private field
okay - so I tried running this example https://clojure.org/reference/atoms
It looks like this example is misleading - it claims that without memoization, the recursive function takes more time
I agree that thatâs a misleading example :)
all itâs doing is memoizing the single outer call, not the inner recursive calls
well, actually thatâs kind of tricky as itâs actually rebinding fib to the memoized fib
depending on your compiler mode (direct linking) that wonât actually work
so it will work in the case presented there (but with some caveats)
seems to work for me - I haven't tinkered with the compiler mode (default) - but I see no difference in times
thank you, this makes a lot of sense. This was driving me nuts for the last 2 hours. peace is resetored
How can I fix this example? Is all this documentation hosted on github or some place like that?
so like I corrected above, this is actually doing what it says
itâs just not particularly obvious how
(def fib (memoize fib))
def
will find the existing var if there is one and re-bind itâs root value (the function)
so is this actually replacing the var fib
with a memoized fib
and the internal call resolves the recursive call via the var (which has changed)
(assuming youâre not using direct linking, which would not do that)
btw, the docs are hosted in github at https://github.com/clojure/clojure-site and issues and prs are welcome there
okay - I will expand this example to include a little bit of this discussion, so it helps noobs like me
if you mean on this atom page, I would keep that brief, but happy to take a look. if youâre sending a PR, you also need to sign the contributor agreement https://clojure.org/community/contributing_site
just one final question - so rebinding the memoized function to itself is then a neat trick to memoize recursive functions?
the big thing to always remember with memoization is that you have created a place to put unbounded unmanaged state
aka a memory leak
this was just posted: https://techblog.roomkey.com/posts/memory-leak.html
itâs exactly that
is it not possible to put a limit on the size of the atom (kind of like chan buffer size in core.async)
there are contrib libs (core.memoize which uses core.cache) that give you memoization but also give you control over the cache, so itâs this idea but productionized a bit
no, you canât limit the size of the atom
yeah, thatâs basically what core.memoize adds, with the option for eviction, expiration, etc
what I want is a (fixed-sized-atom {} ) - I'm thinking I can write a macro to achieve this easily?
I donât think you need a macro for that - a function would fit the bill fine
I'm taking the Up And Running With Clojure course on http://Lynda.com. The person who created the course (Arthur Ulfeldt) suggested I join slack, to get some help with my init.el file. The course has a file downloads section, of which contains the code to pull down the files to setup emacs as a Clojure IDE. Well, apparently the settings in the init.el file are bad, and Emacs displays an error message about retrieving a package. I'm very much new to Clojure, Emacs, needless to say lisp & init.el settings
cappy2112: emacs might not be a good choice for beginners - especially if you have to learn the language and the editor at the same time. LightTable/Nightcode are good editors that will get you up ân running quicker đ for a more conventional IDE, try JetBrainsâ IntelliJ with the Cursive plugin (free trials)
Tell that to @U0EL66M19 Ulfeldt, the instructor for the Clojure course I was trying out, on http://Lynda.com
@cappy2112 you can can ask here: #emacs đ
clojure.spec question: is it possible to change what is returned from conform'ing an input? I have a string in format 'e1234' (so 'e' prefixed to '1234'). I'd like to have '1234' returned when calling conform on that string, is that possible (or idiomatic at all?)
I thought about making a predicate that returned 1234, but that didn't seem to work đ
Oh how nice it would be to have this patch merged: http://dev.clojure.org/jira/browse/CLJ-1496
Get rid of all those (throw (ex-info "Boom" {}))
@pesterhazy i do agree, on the other hand is it not that difficult to wrap exinfo yourself?
@cappy2112 I would suggest to not learn clojure and emacs at the same time. Pick an easier to setup IDE like Lighttable or cursive.
@U0677JTQX tell that to @U0EL66M19 Ulfeldt, he made the course on http://Lynda.com, and recommended emacs with Clojure-specific packages for this course.
@cappy2112 Well, I am not going to argue with him. The emacs vs other editors topic has been dicussed to death. When I did an introductionary at my work for 5 colleagues I chose Lighttable. While it may be not that popular anymore it is easy to setup. The whole development setup took no more than 15 minutes and everybody was set to go. Anyway, I am pretty sure you can follow the tutorial picking a different editor if you do not want to learn emacs. Also, I am not arguing against emacs or cider in general, I think its just to much for a beginner in both spaces.
Yes, I just read a blog post from them about their plans for the future. Even if it was not. I found it the perfect tool for learning, as it shows evaluation results directly in the editor đ
@cappy2112 , checkout spacemacs. lots of stuff pre configured
is anyone aware of how I can setup compojure to write the log msgs into a file instead of stdout??
@plins this is usually configured at the level of your logging system, not Compojure
well theres some logging automatically happening on stdout when I start a compojure-app, any ideas where i should look for instructions?
@plins usually on the JVM you need to configure the logging, depending on your library. Mostly its a configuration file in the resources folder like so: https://github.com/sveri/closp/blob/master/resources/leiningen/new/closp/resources/log4j.properties
$ lein ring server-headless
2017-02-10 11:28:05.317:INFO::main: Logging initialized @1286ms
2017-02-10 11:28:14.157:INFO:oejs.Server:main: jetty-9.2.10.v20150310
2017-02-10 11:28:14.208:INFO:oejs.ServerConnector:main: Started ServerConnector@66b561f1{HTTP/1.1}{0.0.0.0:3000}
2017-02-10 11:28:14.210:INFO:oejs.Server:main: Started @10179ms
Started server on port 3000
@plins here is one with a file appender: http://pastebin.com/hjQY3qCJ
I need to write a parser for a file. I've heard good things about instaparse, but I've never used it. Would y'all recommend it, or is there a different library/approach that people are moving to instead? Would anybody recommend using clojure spec for this? (Happy for threaded replies to keep chatter down on the main thread.)
jeff.terrell: instaparse is alive and well, and is fully awesome. people have experimented with using spec for parsing, but the performance isnât great, and the consensus on slack and on the mailing list AFAIK is to use a parser instead.
@U3L6TFEJF - Thanks, that's helpful. đ
Yeah, +1 on instaparse, I used it to build an interpreter for an old-school text adventure, worked great.
@jeff.terrell Iâd recommend instaparse. I think itâs maybe the best parser Iâve used.
Does anyone know of a library that contains a function to lowercase the keys in an existing map of values? The problem is that when destructuring a map with key of :thekey the actual key might be case-insensitive (e.g. :theKEY or :Thekey or other permutations)
@aaelony used this, canât complain: https://github.com/qerub/camel-snake-kebab
boot.user=> (require '[clojure.string :as s])
boot.user=> (defn mlk [m] (into {} (for [[k v] m] [((comp keyword s/lower-case name) k) v])))
#'boot.user/mlk
boot.user=> (mlk {:a 42 :B 34 :some-Key 28})
{:a 42, :b 34, :some-key 28}
?@aaelony medley (http://weavejester.github.io/medley/medley.core.html) has a map-keys function which you could use.
(meta (assoc (with-meta {} :a) :foo :bar))
is there a way to have meta objects "not survive new -object" ?
so I had the :a attacked to {}, but when I create {:foo :bar}, it's a new object -- I don't want it to inherit the old meta -- is there a way to tell clojure 'when creating new objects, don't preserve old meta object" ?@aaelony: or reduce if you care about number of iterations over it
boot.user=> (defn mlk [m] (reduce (fn [a [k v]] (assoc a (keyword (s/lower-case (name k))) v)) {} m))
#'boot.user/mlk
boot.user=> (mlk {:a 42 :B 34 :some-Key 28})
{:a 42, :b 34, :some-key 28}
you don't need a lib for thiswasn't sure if you needed to descend into maps and check for case or if just a top level sweep was enough
the values are mostly numeric in my specific case, it's just that the key names can be case-insensitive
if you need to walk your map, descending into nested maps and standardize the keys, you'll need something more along the lines of this:
(defn keywordize-keys
"Recursively transforms all map keys from strings to keywords."
{:added "1.1"}
[m]
(let [f (fn [[k v]] (if (string? k) [(keyword k) v] [k v]))]
;; only apply to maps
(postwalk (fn [x] (if (map? x) (into {} (map f x)) x)) m)))
Anyone have any links or guides on best practices for using refs? Iâm using one as an in-memory DB and am curious if thereâs any gotchas I should be aware of
@aaelony (if nested needed check out specter):
boot.user=> (require '[clojure.string :as s])
nil
boot.user=> (use 'com.rpl.specter)
nil
boot.user=> (transform (walker keyword?) (comp keyword s/lower-case name) {:a 42 :b {:and-thIs 28 :c {:some-Key 34}}})
{:a 42, :b {:and-this 28, :c {:some-key 34}}}
Iâm guessing refs arenât that popular because most of the time atoms will do, but when they donât itâs preferred to just use a database?
On closer look, itâs more than Iâm using a ref where a DB makes more sense; for example I need to persist the data across deployments, take backups, etc...
@tolitius, in the off-chance of duplicate keys, I want to concatenate.. e.g. {:ABC 100 :aBC 200 :abc 300} => {:abc "100,200,300"} will need to add that to the specter version
if the map is flat you can just use reduce
(to get you started):
(defn mlk [m]
(reduce (fn [a [k v]]
(update a (keyword (s/lower-case (name k))) conj v))
{} m))
=> (mlk {:ABC 100 :aBC 200 :abc 300})
{:abc (300 200 100)}
A Clojure book I co-wrote is on sale today. Is that appropriate material for #announcements or too commercial/self-promoting?
at least in my opinion (Iâm not an admin here)
if anyone here has submitted a talk to a Cognitect Clojure conf in the past, I have a question on #conf-proposals for you
in clojure, is it possible to xreate an object x such that (identical? x (:self (meta x))) returns true ?
(let [x (atom nil)]
(alter-meta! x #(assoc % :self x))
(identical? x (:self (meta x))))
hmmm. leiningen is suddenly complaining that
Release versions may not depend upon snapshots.
Freeze snapshots to dated versions or set the LEIN_SNAPSHOTS_IN_RELEASE environment variable to override.
What's the best way to resolve this?@aaelony i think that happens when you're referencing something you shouldnt in your deps in your project.clj
i think
export LEIN_SNAPSHOTS_IN_RELEASE=override; lein uberjar
should allow you to actually get your build to run if you're in a rush, but you should probably check out the output from lein deps :tree
to see what snapshot you have in your project
thank-you @tanzoniteblack, that got my build working. What would I look for in lein deps :tree
?
try searching for -SNAPSHOT
if you don't mind sharing the output of that command, I'm happy to take a quick look at it
that's normal when your dependencies have some of the same shared dependencies, but require different versions of them
not the direct cause of the snapshot issue
if you're ok with putting the output of the lein deps :tree
command in a gist on github, I'm willing to take a minute to look over it if you'd like
version ranges can also get you into this
how do you disable logging for your test namespaces, with either tools.logging or timbre?
my preference is to have separate logging configuration in tests that redirects log output to a log file
my current project uses tools.logging and log4j2, so I have a log4j2 configuration file under test/, and because it is under test/ it is used when running tests or a repl or whatever in development from a checkout. I have another log4j2 configuration file that is baked in to the docker container with the uberjar for deployment
it would be tricky, and the exact way to do would depend on what build tool you are using
a related question: right now Iâm doing something like (clojure.tools.logging/info msg)
, but what I want is (clojure.tools.logging/info a-logger msg)
, so I can inject a null logger in the tests
heh, to each his own, I want to gauge my eyes out when dealing with all these Java logger config files đ
the thing is, it takes maybe a day tops of messing around with it, then you never touch it
"10. Get into a rut early: Do the same process the same way. Accumulate idioms. Standardize. The only difference(!) between Shakespeare and you was the size of his idiom list - not the size of his vocabulary."
I have a set of logging dependencies and configuration files that I just copy around everywhere. Some times I do have to update them when, for example libraries started using log4j2 instead of log4j
and it just works, and I shake my head in confusion and wonder what everyone else is doing wrong when they get so annoyed with logginig
Does anyone have experience using clojurefx with an FXML file? I'm having an issue where it loads the FXML, but keeps throwing this exception on load: CompilerException java.lang.NoClassDefFoundError: Could not initialize class javafx.scene.control.ToolBar, compiling:
are there any serious alternatives to tools.logging and timbre in the clojure logging department?
fwiw, I âsolvedâ my problem by creating a test_helpers.clj
containing the line (timbre/merge-config! {:appenders nil})
and requiring that in each test ns
I was having a look at Transit
but I find this sort of CONTRIBUTING file really strange https://github.com/cognitect/transit-python/blob/master/CONTRIBUTING.md
very odd policy for an open source library and even the test files that are needed to run the tests are not in the repo
I probably won't consider transit for Python if I can't even run tests for it, which is a shame since it looked quite interesting
Lets say I have a vec with x elements and want to get the 4 elements from it at arbitrary positions, how would I do that? Basically I want something similar to select-keys, but vor vecs and positions.
(map #(nth my-vec %) [2, 5, 6])
make sure you're aware of the fact that nth
will throw java.lang.IndexOutOfBoundsException
if the number is out of bounds
(common source of bugs whenever I use nth
)
(map #(nth my-vec % default-value) [2 5 6])
will prevent the exception from being thrown
I'm not sure that I knew that nth
took a default value before just looking that up đ
Isnât nth
a linear time lookup? With a vector you can use get
.
Or just the vector itself as a function.
(map my-vec [2 5 6])
if the coll is indexed, nth will do a lookup by index
so not linear
@weavejester you are absolutely correct that that would work as well. And possibly be more performant. I generally try to make sure that all of my code will work with either a list/seq/vector instead of making the code specific to one
@alexmiller Oh really? I thought it was a seq operation and O(n)
that way I can switch between a vector and a sequence produced by having done map
/`remove`/`filter` on it without having to change my code
Has it always been that way?
nth is super weird
Huh. TIL đ
it has many special cases
well, thatâs not the weird part imo
as other coll functions do similar
itâs weird in that most coll functions give you a perf expectation and are not implemented when they canât
nth does an indexed lookup in a bunch of special cases but falls back to sequential lookup
so it kind of is both an indexed collection function AND a sequence function
so is there a standard way to make a *in*
reader with a non-determinant length sequence that I can write to?
https://github.com/clojure/clojure/blob/clojure-1.9.0-alpha14/src/jvm/clojure/lang/APersistentVector.java#L170 apparently there's not really a difference between nth
and get
on vectors đ
@bhauman: PipedInputStream + ByteArrayOutputStream?
@weavejester I'm going to give it a try
You should only need PipedInputStream, not PipedOutputStream⌠I think!
yeah đ
Can anyone see the problem with this code:
(defprotocol Logger
(log
[logger level event]
[logger level event data])
(log-ex [logger level exception]))
(extend-protocol Logger
nil
(log [_ _ _])
(log [_ _ _ _])
(log-ex [_ _ _]))
user=> (log nil :info ::foo)
ArityException Wrong number of args (3) passed to: protocols/eval1345/fn--1346 clojure.lang.AFn.throwArity (AFn.java:429)
Am I going mad, or should it not do that?
It works with four arguments.
@bhauman I think my recollection of pipedinputstream is inaccurate
@weavejester I appreciate the help
Hm, weird, protocols with variable argument lists work on records, but not on nil
.
@bhauman: So a pipedinputstream+pipedoutputstream didnât work?
Thereâs nothing in the docs to suggest that piped streams have timeouts.
I found the solution to my protocol problem though. Turns out that the syntax when using extend
is slightly different to the syntax when inlining protocol implementations in a vector when it comes to overloaded functions.
Sometime I need to write a better-multimethods library đ
I remember there being a good reason why multimethods had pre/post conditions on the defmethods rather than defmulti but can't recall it off the top of my head
It might be another implementation detail; the defmethods just attach functions to the multimethod object.
And pre/post are implemented on the fn
I have a fun puzzle at the moment, I have an atom that has some vectors in it... I want to grab the entirety of one vector that has a specific key... how can I "grab the whole thing when just knowing one attribute" ? let me know if that's not clear enough a query...
@weavejester not sure about that not being a deliberate design choice tho
@sova how are the vectors stored?
note that you can have pre conditions on the multimethods by placing them in the dispatch function
@bronsa Yeah, but again, isnât that because the dispatch function is a function, and therefore has pre/post?
speaking of better-*
, I discovered better-cond the other day and found it pretty nice to use
I'd say that because of the polymorphic nature of multimethods having post condition for each method makes more sense than havingn one to handle all the future defmethods
Yeah, but no reason you canât have both.
Also multimethods donât play nice with namespace reloads. Havenât figured out a good way of solving that one, though.
@wei doesnât work, unless you remove the namespace that has defmulti
. The defmethod
s arenât attached to the namespaces theyâre defined in.
@weavejester (def my-multi nil) (defmulti my-multi dispatch-fn)
is what people usually do
Right, but again you need to wipe the defmulti
My current theory is to have better-multimethods create hidden vars in the namespaces they were defined in.
I think the counter argument is that if you're redefining a defmulti, all the defmethods should be invalidated because you've changed your dispatch funcntion
(CLOS has a way of dealing with that IIRC but we're nowhere near that level of sophistication)
Like:
(defmacro defmethod [sym dispatch & fn-tail]
(let [hidden-sym (gensym (str sym))]
`(do (defn ~hidden-sym ~@fn-tail)
(.addMethod ~sym ~dispatch ~hidden-sym))))
If the namespace is cleared or removed, the multimethods in it are cleared and removed as well.
Well, clearly my implementation isnât great - but add some find-vars etc. in there
Make the gensym predictable based on the key...
But then it would place nice with tools.namespace
.
Alternatively, attach the namespace to the metadata of the function, and let tools.namespace
clear away all multimethods with that metadata.
But that would require changes to clojure.core and tools.namespace, so...
user=> (defmulti foo identity)
#'user/foo
user=> (ns foo)
nil
foo=> (defmethod user/foo 1 [_])
#object[clojure.lang.MultiFn 0x15615099 "clojure.lang.MultiFn@15615099"]
foo=> (methods user/foo)
{1 #object[foo$eval20$fn__21 0x41975e01 "foo$eval20$fn__21@41975e01"]}
Oh, huh. Yeah, I hadnât considered unmunging the function name.
No, but for a dev-time tool that approach definitely has promise.
I just want it for refresh
I might steal that hack, @bronsa đ
There is a public demunge method in Compiler btw :)
@alexmiller if there was any chance of having defmethod include the namespace as meta on the method function that hack would be unnecessary.. just planting the idea :P
Well I'd be fine with that :)
But I just work here