This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2018-03-11
Channels
- # aleph (1)
- # beginners (192)
- # boot (9)
- # cider (12)
- # cljs-dev (223)
- # clojure (30)
- # clojure-brasil (3)
- # clojure-china (1)
- # clojure-italy (4)
- # clojure-russia (24)
- # clojure-spec (7)
- # clojured (5)
- # clojurescript (82)
- # cursive (9)
- # datomic (24)
- # emacs (6)
- # fulcro (9)
- # keechma (1)
- # luminus (1)
- # off-topic (3)
- # om-next (5)
- # onyx (1)
- # parinfer (9)
- # re-frame (1)
- # reitit (4)
- # ring-swagger (6)
- # shadow-cljs (8)
- # spacemacs (1)
- # sql (1)
- # unrepl (13)
I bet you can even get fancier by using something like component
to try to preserve state in the face of reloads.
delay is useful for situations where you might want to evaluate some code, but not yet, and if you do you might use the value multiple times but only want to calculate it once
like a lazy-seq but it's just one value
Hi! I'm trying to get Sente to work. Right now client and server seem to be connected (I see ping messages). But when I try to push a message from the server to a client like this ((:send-fn channel) "dabecca4-ca3a-496a-9016-cf46ddc34f45" [:sample.event/some-id {:data "data"}])
, I get the following error: java.lang.IllegalArgumentException: No implementation of method: :pack of protocol: #'taoensso.sente.interfaces/IPacker found for class: taoensso.sente.EdnPacker
I have been staring at the code for a couple of hours now and can't think of anything else to try
Hey peeps, I'm using Brave and True to learn Clojure and I've noticed that it doesn't even mention the for
iterator. Is that intentional you think? Is using for
- unless absolutely necessary - regarded as bad form in Clojure?
@nikoszp I think they don't mention it because it's not that often used. Most cases where you could use for, it's more idiomatic to use map, reduce, or doseq. It's useful to generate multiple elements from a list for example.
Guys..
I have a list :
(def mylist '() )
How do I write a function that adds elements to the list by user input without the use of atoms
Why no atom? Clojure is immutable by default, but you could use a transient vector to store them which is mutable, or use java interop and use a java list. But really one of the greatest things in clojure is the atom, cause it's a very nice and easy way to work with concurrency.
@suryapjr Sounds a bit like you still need to get into a functional mindset! 🙂 (conj mylist the-new-input)
will return a new list with the element added. You'll use this new list in whatever coming function calls you're performing. What is the end goal in your program? It will be a bit easier to help if you elaborate some more.
PS: Using the list literal '()
is fairly uncommon (in fact, I've never seen it in production code). Vectors []
is the data structure people tend to use for ordered collections.
(conj mylist input) returns a new list which has to assigned to a variable using def or let ..but since I don't know how much elements will be added in the future,I can't bind values to def ..
I try to avoid atoms as much as possible unless there is no other way to do something (usually something inherently stateful from "the outside world" such as a database connection)
@suryapjr I'll try to write up a quick example of a more functional user input loop, just a sec!
Eventually you want to have state somewhere, it's easier to have it in an atom than external. If you just want to use the list for something else you don't need an atom.
@gklijs @suryapjr transients need to be used as if they were not mutable, and there is no such thing as a transient list, only associative data is transient and lists are not associative. If you use transients as if they were mutable (not using the return value) you will lose data.
Here is an example of updating a list based on a user input loop:
(defn user-input-loop [input-list]
(let [user-input (read-line)
updated-list (conj input-list user-input)]
(println updated-list)
(when-not (= user-input "quit")
(recur updated-list))))
(defn start-input-loop []
(user-input-loop []))
@suryapjr Try to see if you understand this example. The gist of it is that we are calling the user-input-loop
function over and over again (with recur
) using the new, updated list as an argument.
@pooboy @gklijs transients can't model identity and I would definitely not suggest it to a beginner
It's just a small convenience so we don't have to give an empty vector as an argument when we start the user-input-loop
. Basically just a habit of mine!
@suryapjr Consider this example
(defn foo [x]
(if (zero? (rem x 107))
x
(foo (inc x))))
and what happens to the stack if you call it with (foo 110)
.
You can eliminate the stack use by replacing foo
with recur
:
(defn foo [x]
(if (zero? (rem x 107))
x
(recur (inc x))))
In this case, the recur
target is foo
. There is a more general form where you can use loop
as your target, but this illustrates the general idea. It ends up feeling like an imperative loop, and in fact it has the same performance, but it remains a functional construct.@suryapjr Sometimes it helps me to see the code generated for these things. If you start up Lumo or Planck with the -v option (for verbose) you would see the JavaScript generated for each, which might help in seeing what it does in a more familiar language. The first produces
cljs.user.foo = (function cljs$user$foo(x){
if((cljs.core.rem.call(null,x,(107)) === (0))){
return x;
} else {
return cljs.user.foo.call(null,(x + (1)));
}
while the second produces an actual imperative loop, involving an assignment to x
:
while(true){
if((cljs.core.rem.call(null,x,(107)) === (0))){
return x;
} else {
var G__22 = (x + (1));
x = G__22;
continue;
}
break;
}
regarding style there is https://github.com/bbatsov/clojure-style-guide
@suryapjr A couple of lessons to learn:
1) Don’t try to create very compact, terse code. Use (fn [ ] ...)
instead of #( ... )
more often than you might initially think.
2) Try to break things apart. You can end up with a function that essentially looks like a gigantic single equation on a blackboard, which is hard to read. Find the pieces inside of it and break them out into separate functions.
Having said the first item above, there is definitely a balance, and some constructs leading to shorter code make it more readable. For example, using destructuring. And, if you can express an idea more succinctly with less code, it can be more readily understood. Just don’t try to squeeze it down beyond where it becomes hard to read.
Another bit of advice for readable code is to not to initially worry too much about performance. Write code that is clear and if it is fast enough, then you end up with a readable result. 🙂
@suryapjr and take the clojure-style-guide with a grain of salt. Most devs I know have more than a few objections with it. To a pirate from a movie: "it's more of what you call guidelines than actual rules".
@tbaldridge noted !!
you can learn them both. 90% of the languages is the same, it's only when you dig into more complex topics that the differences show up.
How should I proceed? I did this ..
(import java.util.ArrayList)
(def a (new ArrayList))
@suryapjr right, a.add(42)
in Java becomes (.add a 42)
in clojure
When I was importing the Java.util.Random library , I had done this :
(.nextInt (java.util.Random). 100)
https://clojure.org/reference/java_interop lists both of those next to each other - I think they're the same
Why was it so important not to implement contains?
over lists, in clojure core? how would you support that design decision? thanks!
one of the principles underlying Clojure's library of functions is that everything has a consistent performance profile. contains?
only doing a key lookup means it's always as fast as a key lookup; if it were to support lists as well it would be slow for those cases because the only way to check if a list contains a value is to iterate through it from the start to the end
this is the same reason that e.g. conj
adds to the head for lists but the tail for vectors
But, perhaps you are asking a different question; you can do (.indexOf '(:a :b :c) :b)
in both Clojure and ClojureScript
Using the example from that post
(def beatles ["John" "Paul" "Ringo" "George"])
(not (neg? (.indexOf beatles "Ringo")))
Thanks a lot, for reminding me of the reason. I knew there was a logical reason but couldn't recall it.
contains?
works on sets maps and vectors (but on vectors it tests on index, not on element equality)
@suryapjr As an exercise, if you try to write my-when
above as a function, you will come away understanding why it needs to be a macro
When we call java in clojure..take the example of a linked list ..we can mutate the object.. immutability is switched off during interop with Java ?
no, you can mutate
you’re just making the exact same call you’d make in Java, with the same effects
@suryapjr immutability isn't a property of Clojure the language itself, it's a property of the data structures Clojure uses. Java has immutability for e.g. strings, but for most other data structures in Java, you mutate to use them (even from Clojure).
Clojure's strings are in fact just Java strings (since they're immutable):
=> (type "")
java.lang.String
you can also use Clojure's immutable data structures from Java, just like you can use Java's mutable data structures from Clojure
Hey all, for the new clj --main cljs.main --compile hello-world.core --repl
command. This is going to implicitly look for hello-world.core
within a src
directory, yes? How can I change where this command looks for my namespace?
Nice. Thanks!
https://github.com/clojure/clojurescript/wiki/Using-cljc#general-considerations this seems to say that src/cljc/project-name
is acceptable. but when using the clj command line tool its not finding this. is there something i'm doing wrong?
[dan@localhost paths]$ tree
.
├── deps.edn
├── scripts
│ └── run
└── src
└── cljc
└── paths
└── paths.cljc
if src/cljc is on your path, you should be able to require paths.paths
clj
sees it automatically when its at src/paths/paths.cljc
but not with the intermediate level of cljc folder there
then you need to make sure src/cljc is on your classpath
I wouldnt' expect that to be automatic
also, separate folder structures for clj/cljc/cljs isn't needed, but it is a convention some people like
once src/clj, src/cljc, and src/cljs are all on the classpath, as far as clojure is concerned the stuff underneath could be in any of those directories
thanks. i'm just now venturing into cljc territory and want to use clj. a lot of moving parts 🙂
Question about clj --main cljs.main
and the watch
option
If I have a directory structure like this:
test
src
test.cljs
deps.edn
How would I run watch
on the above? I have been trying clj --main cljs.main --compile test --repl --watch test
or clj --main cljs.main --compile test --repl --watch src
Further, it is my understanding that running watch
will recompile my test.cljs
file when a change is found on file save?
(Yes, single segment names are not good, I am just playing around 🙂 )For anyone who gets stumped on this, the order of the --watch
CLI option seems to matter. To get this to work:
clj --main cljs.main --watch src --compile test --repl
matan use pr-str instead of str
So say I have this function:
(defn regex-escape [s]
" turn a regex agnostic string into its corresponding escaped regex string "
(str
(map
#(if (clojure.string/index-of "#$()*+.?[^{|\\" %)
(str "\\" %)
%)
s)))
pr is what the repl uses to show values, so if you directly return the lazy-seq to the repl you will see the right thing
use apply str instead of just str in that code
because the string form of the lazy-seq still isn't what you want
@matan to be clear: (str (map ...)) gives a silly object notation, (pr-str (map ...)) is a string of a list of things, (apply str (map ...)) is the string made of each thing returned by map
user=> (str (map identity "hi"))
"clojure.lang.LazySeq@10c2"
user=> (pr-str (map identity "hi"))
"(\\h \\i)"
user=> (apply str (map identity "hi"))
"hi"
and for symmetry
user=> (apply pr-str (map identity "hi"))
"\\h \\i"
tinkering it after solving my itch, this is a little confusing:
=> (str ["3333" "3333"])
"[\"3333\" \"3333\"]"
that's the string representation of a vector of strings - it looks better if you call println on it
I don't think you made an error - I'm just saying that's why it looks like that
it's a little odd since (str "foo") isn't "\"foo\""
I wish to share something more abstract. Compared to typed languages, I find that for me writing clojure creates a lot of technical debt: it is simple to put together a small library, but then unless I sprinkle type and shape checking all over the place, it is close to impossible to evolve and maintain the code later on. Any caller can easily abuse my code with wrong input typing, and most of all, I'd find it hard to follow what types a function expects when I come back to old code.
i know of at least one company that moved away from core.typed and towards schema, though: https://circleci.com/blog/why-were-no-longer-using-core-typed/
@sundarj well thanks, I guess above all this suggest that they'll also drop spec and clojure, as it is very much core to how clojure programming really works for projects that aren't small!
So if I need to deliver and maintain quality code, I end up working harder to type-check stuff with my own lines of code, compared to a typed language, and using spec
for that isn't that elegant/compact compared to typed-languages.
@matan I've had these same problems
part of this is a trade off for lisps - I'm very interested by the addition of extensible variant types in recent OCaml versions (but this goes into off topic)
@matan One thing: I would point you to prismatic/schema instead of spec. spec so so heavyweight that i found myself avoiding it. schema has a much lighter syntax and does the thing I care about the most: check the shape of the map while acting as internal documentation. if you’ve ever used flow type or typescript, the feel of schema is very similar
using spec with the purpose of checking incoming data and acting as internal documentation is made much better by https://github.com/metosin/spec-tools#data-specs
I still get caught out by some of the complexity of spec. Like instrumenting functions that have side effects, for example.
Hi everyone 👋 Curious if anyone knows how easy it would be to get a nested sequence collection based on knowing a value within the sequence?
For example, given [(:foo :bar) (:baz :bat)]
and I know :bat
, I would like to get (:baz :bat)
(->> '[(:foo :bar) (:baz :bat)]
(filter #(= (last %) :bat)))
Won't necessarily be the last item though 🙂
Guessing I could use filter
with something like contains?
yep, basically you need filter
, also you'd want to use first
since filter
returns a coll
if you need more advanced filtering consider specter
Cool, thanks. Trying to avoid extra libraries on this one as it's a learning exercise 🙂
filter returns a lazy-seq, which doesn't work with contains?
contains? is specifically for associative structures, and only looks by key
user=> (contains? '(a b) 'b)
IllegalArgumentException contains? not supported on type: clojure.lang.PersistentList clojure.lang.RT.contains (RT.java:814)
user=> (contains? '[a b] 'b)
false
user=> (contains? '[a b] 1)
true
user=> ('[a b] 1)
b
i think he was talking about the test used for filtering, such as
(->> '[(:foo :bar) (:baz :bat)]
(filter #(contains? (set %) :bat)))
implying the input sequences are actually meant to be sets
oh, right, I misread
@noisesmith just come back to slack. I am hitting that exact issue re lazy-seq and contains? not supporting lazy-seq
right, if you have a specific question about my example above let me know - the simple thing might be to call set on the thing first
Perfection. Thanks @noisesmith. I wrapped my %
in my anonymous function for the contains?
and it sorted the issue
TIL 🙂