This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2017-09-27
Channels
- # beginners (34)
- # boot (15)
- # cider (7)
- # cljs-dev (7)
- # cljsjs (2)
- # cljsrn (46)
- # clojure (130)
- # clojure-argentina (1)
- # clojure-colombia (2)
- # clojure-greece (1)
- # clojure-italy (53)
- # clojure-losangeles (1)
- # clojure-russia (15)
- # clojure-spec (8)
- # clojure-uk (100)
- # clojurescript (117)
- # core-matrix (1)
- # cursive (24)
- # datomic (41)
- # duct (1)
- # emacs (11)
- # fulcro (22)
- # graphql (4)
- # hoplon (3)
- # jobs (1)
- # lein-figwheel (3)
- # luminus (18)
- # lumo (52)
- # off-topic (57)
- # pedestal (2)
- # planck (12)
- # re-frame (22)
- # remote-jobs (1)
- # ring-swagger (6)
- # rum (7)
- # shadow-cljs (13)
- # yada (19)
Hi there, clojure noob trying to understand the language concepts and basic structures. May I ask for some clarification? I’m trying to build a prime-number-seq generator using lazy-seq and the idea from the Sieve of Eratosthenes. This is the code I wrote:
(defn primes
([]
(concat
(sorted-set 2)
(primes (remove #(= (mod % 2) 0) (drop 2 (range))))))
([s]
(let [x (first s)]
(cons x
(lazy-seq (primes (remove #(= (mod % x) 0) s)))
))))
It works for getting, for example, the first 1700 primes from the sequence. When I ask for the 1772th prime number, I got a Stack Overflow. From the research I did, I suspect that this has some to do with head retention but I can’t see where is the problem. Any ideas?I realize this is for learning purposes and hence not what you're asking, but fwiw there's a great SoE example using core.async: https://github.com/clojure/core.async/wiki/Sieve-of-Eratosthenes
those calls to (lazy-seq (primes (remove
build up and so sooner or later you blow the call stack whilst attempting to chew throrugh them
is tangentially related
Thanks a lot @U2TCUSM2R @ben.hammond . I think that I did not got lazy-seqs the right way and I’ll do some homework on this topic before trying to move on
why are you passing s into the recursive call when you know that the first element will never be used?
In fact I’m passing it around just to capture the first element and discard all multiples of it
I'm not sure this causes your problem, but it's definitely making your code do redundant work
I think the issue is that the nested remove calls each add to the depth of the stack needed to realize the next item
by the time you get to the Nth prime you are executing (first (remove f (remove g (remove h (remove ....... coll))))))
to get x
if instead of nesting calls to remove, you pass in a set (and add an item on each recursive call) you can keep stack usage constant instead of having it grow linear with N
also, the usage of (sorted-set 2)
is bizarre, because concat instantly removes all the sorted-set properties and leaves a simple lazy-seq, it would be simpler to do (cons 2 ...)
I didn’t really know about this but thanks for the clarification. I’ll try to investigate the relationship between seqs and its interactions with the collections implementations
a good rule of thumb is that anything lazy turns its result into a LazySeq - nothing lazy ever preserves the type of its input collection
(unless by coincidence the input was already lazy)
@jeaye just saw https://blog.jeaye.com/2017/08/31/clojure-code-quality/ -- nice work
you should consider adding joker to the list - its linter mode works wonders and works for cljs: https://github.com/candid82/joker
we use it on CI to check for unused namespaces at least, and locally as an emacs mode to catch some errors early (like eslint)
whats the most idiomatic way of keeping tabs on an element of a collection? Do I store the index of the element or do I store the element and do some sort of lookups, or perhaps something else entirely?
er, depends if your collection is a a vector or a map or a set or a list
hmmm. That actually simplifies my use-case indeed 🙂
I could probably use the element itself and a combination of fnext
and select
(let [x (calc-x)]
(when (pred? x)
(do-something-to x)))
I feel like this is something I could use. I like when-some
, when-first
, etc. Is there a more idiomatic way I should be writing this?(some-> x calc-x pred? do-something-to)
?not necessarily an improvement though
@ben.hammond I think that only works if pred?
returns what you gave it for "true" and "nil" for false?
there is cond->
too, but i guess for a single condition-function pair that might be overkill
that code you originally posted looks clear to me
@sundarj cond->
doesn't take the previous value in for the predicate though, (cond-> (calc-x) pred? do-something-to)
wouldn't work
It's definitely clear, I've just been a little spoiled by:
(when-first [a [nil]]
(println a))
(whenp pred? [x (calc-x)]
(do-something-to x))
i guess you could write this macro if you fancied it 😉I didn't think there was anything better, but I thought I'd fish in case I could rephrase it differently so there was no intermediate value.
I don't understand the difference between https://clojure.github.io/clojure/branch-master/clojure.core-api.html#clojure.core/binding https://clojure.github.io/clojure/branch-master/clojure.core-api.html#clojure.core/with-bindings
can any of youse point me at an explanation ?
is it that with-bindings
creates a thunk that closes over the new value, and thus handles multi-threading better?
@ben.hammond one does bindings via a {}
, one does it like a let
in a []
yeah but must diff by more than just syntax
I remember reading about a book someone was writing that was a annotated read-through of the clojure.core source code. Does anyone know what I'm talking about and can point me to it?
I'm experiencing a strange issue where when I'm recompiling a test namespace (clojure.test based) after any change I get an error that all my other required namespace aliases already exist:
Caused by java.lang.IllegalStateException
Alias sut already exists in namespace project.account-test,
aliasing project.account
This is how the imports look:
(ns project.account-test
(:require [project.account :as sut]
[project.account.event-handlers :as account-events]
[clojure.test :refer :all]))
The only way I've managed to resolve it (until the next change) is to restart the repl 😞
(ns-unmap 'project.account-test 'sut)
didn't help, just as (reloaded.repl/reset-all)
doesn't help.
It's really annoying. Any idea what might be causing this?The macro that @sundarj mentioned above (more or less) https://gist.github.com/madstap/52f280f17289f1a1ec81f3c9f0b23778
@pesterhazy Thanks for the suggestion! Joker slipped by, but I'll give it a go on this code and add an entry to the post.
@vinai ns-unmap is for vars, not for aliases
@vinai to remove an alias to another ns as created by require / :as - use ns-unalias
Thank you @noisesmith, good to know. That allows me to clean up the mess manually. I still am curious why that is happening though.
if you use refresh, that deletes a namespace and replaces it
aliases aren’t by namespace name iirc, but by their object identity(?)
so my theory is that the new namespace has the same name but isn’t the one aliased
(it would require some experimentation to verify this) - regardless, the simpler solution might be to also refresh the test namespace (which does the same thing to that one as well, deleting it entirely and recreating it)
This may be more of a java question, but I've got a clojure service behind a KafkaConsumer that I've had to trim and expose as a gen-class that another service can call directly as a class/library for performance reasons, rather than going through kafka. How do I keep the quick development cycle on the clojure side without having to compile down to an uberjar and copy it into the other project (and then restart that other service) on every change? What was nice as a kafka consumer was that the service respected the reloaded workflow so a change was as simple as a (reset) in the REPL
the interface class is hosed, whatever you're generating with gen-class if you make a change there you're going to have to restart
@dadair if you use clojure.java.api.Clojure.var to look up the function to call, it will see redefinitions every time you invoke it
then you don’t need gen-class either, just use require
to make clojure load your code, and Clojure.var to look up the var you can call
require
won't reload files if they've changed though fyi, that's where you need tools.namespace
or, you can make sure you have a layer of indirection between the ns that uses :gen-class and the code you are calling, so that if you reload the clojure code in the process, the gen-class methods call the new definition
@bfabry it takes a :reload arg, but that’s not what I was talking about, I was talking about the usage flow when not using gen-class - you need to remember to call require before using your code
well unless you tell it to using :reload/:reload-all. but tools.namespace is a bit cleaner because it clears out old vars
the reloading part is separate, I was just describing how to replace gen-class
are there any performance considerations (on the order of ms) between using a (gen-class ..)
and using clojure.java.api.Clojure.var
?
the noticible difference is on initial load (what would happen on startup in the case of gen-class, or on usage of require in the Clojure.var use case)
Noob question. How can I get (clojure.repl/source my-function)
to work in a lein repl?
Just getting “source not found”
@chalcidfly by loading the definition from a file instead of typing it into the repl
the source function needs to know a file and line number, clojure doesn’t actually store the raw source of the code it compiles in memory
Using load-file
?
That doesn’t seem to do anything for me
sure - that’s what cider etc. are doing
load-file ensures that the metadata is present that allows repl/source to operate
I’ve got (defn add-stuff [x] (+ x x))
in a file, I use load-file, and clojure.repl/source still says Source not found.
… checking
breeze.mast.services.accounts-test> (meta #'permission-for)
{:arglists ([perm perms]), :line 37, :column 46, :file "*cider-repl localhost*", :name permission-for, :ns #object[clojure.lang.Namespace 0x73f10384 "breeze.mast.services.accounts-test"]}
breeze.mast.services.accounts-test>
breeze.mast.services.accounts-test> (meta #'permission-for)
{:arglists ([perm perms]), :line 44, :column 1, :file "/home/dan/ops/projects/breeze_ehr/mast/test/breeze/mast/services/accounts_test.clj", :name permission-for, :ns #object[clojure.lang.Namespace 0x73f10384 "breeze.mast.services.accounts-test"]}
@chalcidfly oh, the other gotcha is the file needs to be in the expected place on classpath. source is an odd little macro.
Oh. what’s the default cp for lein repl?
@chalcidfly use lein cp
to see it
or more accurately I guess lein with-profile repl cp
(typo fixed, wants string not keyword)
I’ve got clojure-projects/expand/src on there, do I need clojure-projects/expand/src/expand as well?
no - as long as the ns-declaration in your file matches the path from src to the file
Weird. Still doesn’t work.
what if you use (require 'some.ns :reload)
instead of load-file
That works!
odd that it would need that…
Thanks a million for your help, idk what was going on with load-file there
@dpsutton a namespace loaded via load-file means that repl/source doesn’t work - I verified this myself
there’s only one way to use load-file, you give it a string with the path to the file
(well maybe you could also give it a java.io.File
object, haven’t tried, but I wouldn’t expect this to act differently either0
if you’re in a place where you you’re wishing you had multi-arity anonymous functions, is it safe to say that you’ve overcomplicated things? 🙂
you can do multi-arity anonymous functions
(fn ([] 0) ([x] 1))
and I’d say no, not necessarily :)
@alexmiller hallelujah!
; f r
Does anyone have advice for introducing clojure at work? I have a prototype in clojure for replacing some really gnarly xslt stuff and I’m going to be proposing switching to it to the team sometime this/next week. Curious if others have had success or failures introducing it to a non-clj workplace.
What's the rest of the stack? any jvm? Good place to focus on a similar deployment / prod environment / toolchain
It’s mostly a python shop in our area and we’re pretty functional with python. Farther towards the front-end there’s a lot of scala use. The part I’m proposing replacing is actually a Java program to run XSLT transformations and the .xsl files required to transform them, so to some degree I’m replacing one non-standard piece of tech with another one (and I think it’s fair to say that almost everyone would rather learn clj than xslt)
is there a threading operator that given a value keeps threading until a return value is not nil
and then breaks early?
@beoliver that is what oops, I misread, that doesn’t exist, but you can use some->
and some->>
areor
what would be threaded, since you expect things to return nil until one doesn’t
@noisesmith good point
that would be a straightforward macro to write, the hardest part would be a decent name for it
oh wait, is this some-fn?
@beoliver oh, yeah, this is some-fn
clojure.core/some-fn
([p] [p1 p2] [p1 p2 p3] [p1 p2 p3 & ps])
Takes a set of predicates and returns a function f that returns the first logical true value
returned by one of its composing predicates against any of its arguments, else it returns
logical false. Note that f is short-circuiting in that it will stop execution on the first
argument that triggers a logical true result against the original predicates.
=> ((some-fn :a :b :c :d) {:c 2 :d 3})
2
be aware that when given N args, it checks each arg separately as an arg to each fn
#(reduce (fn [_ f] (some-> % (f) (reduced))) nil fns)
would do it
but I think some-fn is still clearer
(apply some-fn fns)
is equivalent to the above
@noisesmith I think the some-fn
will work perfectly