This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2020-04-01
Channels
- # announcements (21)
- # architecture (6)
- # aws (18)
- # babashka (14)
- # beginners (231)
- # boot (1)
- # calva (2)
- # chlorine-clover (22)
- # cider (34)
- # clara (16)
- # clj-kondo (53)
- # cljdoc (5)
- # cljs-dev (22)
- # cljsrn (3)
- # clojure (283)
- # clojure-europe (24)
- # clojure-italy (9)
- # clojure-nl (5)
- # clojure-spec (5)
- # clojure-uk (57)
- # clojurescript (14)
- # core-typed (8)
- # cursive (4)
- # data-science (11)
- # datomic (41)
- # docker (24)
- # duct (2)
- # emacs (2)
- # exercism (29)
- # fulcro (96)
- # graalvm (4)
- # jobs-discuss (1)
- # kaocha (53)
- # lambdaisland (20)
- # malli (5)
- # nrepl (4)
- # observability (7)
- # off-topic (40)
- # pathom (44)
- # pedestal (8)
- # re-frame (19)
- # shadow-cljs (58)
- # spacemacs (2)
- # sql (9)
- # tools-deps (15)
- # vim (3)
- # yada (10)
Have a stupid question 😞 Why doesn't this function to generate a fibonacci sequence of length n work?
(defn createFib
([length] (createFib length [0 1]))
([length a] (if (= (count a) length) (a) (recur length (conj a (+ (nth a (- (count a) 1)) (nth a (- (count a) 2))))) )) )
@negatifzeo (a)
means "call the function a with no arguments"
Oh my gosh, so simple, And it works!
Thanks!
user=> (let [a [1 2 3 4 5]]
[(= (nth a (- (count a) 1))
(peek a))
(= (nth a (- (count a) 2))
(peek (pop a)))])
[true true]
(fixed)@noisesmith I like that!
Now I have another question... I get an integer overflow before long
How would I use longs or big ints?
use +'
instead of +
One more.... What does the N at the end of a very large number indicate?
user=> (type 1N)
clojure.lang.BigInt
it's a read/write notation for BigInt
Beautiful. Thank you!
(you only see it with very large numbers usually, but even 1N is a bigint)
related
user=> (type 1M)
java.math.BigDecimal
Great!
Not sure if I would have found this had I not asked here
@negatifzeo if you can figure out the right regex, clojure.repl/find-doc
can help a lot
user=> (find-doc #"\Wsum\W")
-------------------------
clojure.core/+
([] [x] [x y] [x y & more])
Returns the sum of nums. (+) returns 0. Does not auto-promote
longs, will throw on overflow. See also: +'
-------------------------
clojure.core/+'
([] [x] [x y] [x y & more])
Returns the sum of nums. (+') returns 0. Supports arbitrary precision.
See also: +
-------------------------
clojure.core/unchecked-add
([x y])
Returns the sum of x and y, both long.
Note - uses a primitive operator subject to overflow.
-------------------------
clojure.core/unchecked-add-int
([x y])
Returns the sum of x and y, both int.
Note - uses a primitive operator subject to overflow.
nil
sadly the doc strings are not optimized for regex searchability, but the facility does exist
bonus, it's not limited to core - it works with every defined function with a doc string
Also, can I ask what you use to format your code so that it's so readable?
here in slack I use the standard markup three ` introduces a code block, there's also a button for it
The final form:
(defn createFib
"Usage: (createFib n), creates a fibonacci sequence of length n"
([length] (createFib length [0 1]))
([length a] (if (= (count a) length) a (recur length (conj a (+' (peek a) (peek (pop a)) ))) )) )
Just a note on Clojure style, we use kebab-case
rather than camelCase
for names.
Any suggestions for porting https://github.com/pomber/didact/blob/master/didact.js to Clojure? The mutable tree structure of fibers is throwing me for a loop. Zippers came to mind, but there are several references to locations within the tree at the same time which complicates the matter considerably.
does clojure have an all
function? (apply and [true true false])
doesn't work i guess because and
is a macro
oh, every?
never mind me
HI Everyone. I have a problem with is
in clojure.test . Is there an is-not
I can use? If I simply test (is (not ...))
then the failure messages are uninformative. If (is (> a b))
fails, I get a message like (not (> 1 2)
but when (is (not (> a b)))
fails I just get a message (not (not true))
. Certainly for >
I could choose a better predicate for the test, but in general (is (f a ...))
vs (is (not (f a ...)))
is problematic.
(deftest t-nullable
(let [a 1 b 2]
(is (> a b))
(is (not (> b a)))))
(run-tests 'clojure-rte.core-test)
FAIL in (t-nullable) (form-init4386036104585295471.clj:33)
expected: (> a b)
actual: (not (> 1 2))
FAIL in (t-nullable) (form-init4386036104585295471.clj:34)
expected: (not (> b a))
actual: (not (not true))
Is there a cousin of isa?
which tests not type inclusion, but rather type intersection? I.e. given two isa?
compatible type designators how can I know whether there can exist an object which is a member of both types?
Not directly,but you can call ancestors
on both, and then do a set intersection on the sets they return: https://clojuredocs.org/clojure.core/ancestors
@didibus, does it suffice to call ancestors
once for A
and once for B
and find the intersection of those two results, or do I need to walk up the return value and keep calling ancestors
?
E.g., does this suffice? Note, that I'm calling not-any?
twice rather than calling intersection
, because I don't need the intersection, I just need to know whether the intersection is empty.
(defn disjoint? [t1 t2]
(let [ancestors-1 (ancestors t1)
ancestors-2 (ancestors t2)]
(and (not-any? (fn [a2] (contains? ancestors-1 a2)) ancestors-2)
(not-any? (fn [a1] (contains? ancestors-2 a1)) ancestors-1))))
This implementation is sadly wrong. 😭 It asks whether the two types have a common supertype, not whether they have a common subtype.
I believe it should be the following:
(defn disjoint? [t1 t2]
(let [descendants-1 (descendants t1)
descendants-2 (descendants t2)]
(and (not-any? (fn [a2] (contains? descendants-1 a2)) descendants-2)
(not-any? (fn [a1] (contains? descendants-2 a1)) descendants-1))))
Found another bug in this function disjoint?
Here is my current implementation
(defn disjoint? [t1 t2]
(and (not (isa? t1 t2))
(not (isa? t2 t1))
(let [descendants-1 (descendants t1)
descendants-2 (descendants t2)]
(and (not-any? (fn [a2] (contains? descendants-1 a2)) descendants-2)
(not-any? (fn [a1] (contains? descendants-2 a1)) descendants-1)))))
The previous version was answering false in the case one type isa?
subtype of the other
Hum, I believe ancestors will return the following chain of parents, so you shouldn't have too walk up it
I think that's the difference with the parents
function, which will only return the immediate parents, ancestors I think will walk up the parents and aggregate their parents and their parents parents all the way for you
Looking at the documentation for https://clojuredocs.org/clojure.core/type I see how to find a type of an object. And in the see-also section it talks about the function `instance?` which tests whether an object is a member of a designated class. Is the documentation using the word class and type interchangeably here? What is the correct way to check type membership, assuming I have a type designator compatible with `isa?` ?
According to the doc:
user=> (doc type)
-------------------------
clojure.core/type
([x])
Returns the :type metadata of x, or its Class if none
From what I've seen, it looks like type
/`isa?` and class
/`instance?` are counterparts with each other.class
and instance?
dealing strictly with java object hierarchy; type
/`isa?` deal with derived types, falling back to Java classes if no derived type hierarchy is available.
No, as far as I understand isa?
takes two type designators and tells whether one is a subtype of the other. I'm looking for a function which takes an object and a type designator and asks whether the object is a member of that type.
i.e., something that can be called like instance?
but which accepts any 1st argument which is compatible with isa?
@jimka.issy (isa? (type x) y)
?
and since you mention you have an isa?
compatible type designator, type
would make more sense to me.
Good suggestions.
Thanks. But since I really don't understand all the flexibility of isa?
, what's the best way to test my code? How can I generate a huge set of isa?
compatible arguments and corresponding instances? Perhaps I could look at the testing code for isa?
itself? Does anyone know how to locate that?
Hi penryu, for the moment here is what I think I'm doing. I'm implementing a DSL which lets the user talk about types. I want to claim on my DSL that I accept any type which isa?
supports.
iiuc, as long as your program uses type
, isa?
, or by extension defmulti
/`defmethod`, this is implicitly true.
I'd like to write a function which takes a single argument and distinguishes several cases: (1) anything other than list, (2) empty list (3) singleton list (4) non-singleton list. Can someone suggest the most idiomatic way of doing this?
(cond (not-a-list x) ...
(empty-list x) ...
(singleton-list x) ...
(non-trivial-list x) ...)
Here is what I'm trying.
(cond (not (list? pattern)) ...
(= pattern ()) ...
(not (rest pattern)) ...
:else ...)
Based on what I know of your question, I might start with something like:
(def do-stuff [x]
(if (sequential? x)
(case (count x)
0 (do-empty x)
1 (do-single x)
(do-longer x))
(do-not-list x)))
This handles sequences other than actual lists (eg, vectors) as well. If you're expecting the method to be called with different types, you might consider multimethods.
Using clojure.jdbc
I would like to write a method that does update-or-insert-rows [db table rows where]
where rows could be a seq of maps.
this would work for 1x row:
(defn update-or-insert [db table row where]
(sql/with-db-transaction [t-conn db]
(let [result (sql/update! t-conn table row where)]
(if (zero? (first result))
(sql/insert! t-conn table row)
result))))
Is there any way using insert-multi!
or doing a batch operation and not calling this method for each row? assuming my DB would need to update some data.
or a way to use ON DUPLICATE KEY UPDATE...,
I can also delete > insert - which I prefer not to
you might want to just call sql/execute!
with a statement that has the on duplicate key update...
clause
yea but i'm looking for some abstraction, as I would need to parse all given maps... etc to query,
@aviv The problem (from a library point of view) is that upserts have different syntax across different databases, and there are also different ways to implement upsert even for a single DB, depending on exactly what semantics you want and what trade offs you want to make.
How would you tackle this kind of scenario? 🙂 @U04V70XH6
@aviv When I researched this for MySQL (which is what I use at work), I found three completely different approaches with three different sets of trade offs, so the approach I would code up would very much depend on the specific trade offs I was willing to accept in those specific circumstances.
We write upserts quite often at work, but never for bulk updates/inserts -- they are always single row solutions -- and we do it in different ways depending on all sorts of parameters to the problem (how write heavy the table is, whether a double insert actually matters (and whether it is detectable through key constraints -- it isn't always). So the logic varies a lot.
If I was using PostgreSQL, I would no doubt have the option of different solutions, with different trade offs, due to the different syntax/semantics that PG provides compared to MySQL.
I see, by double insert you mean duplication. we use MySQL and currently I choose to batch delete & insert compared to upsert-each-row of the batch
I could test it timing as this is my only concern atm
When deleting and inserting, there's also the consideration of what happens if another process queries for the record concurrently and doesn't find it.
For some tables, it's safer for us to do an insert, then delete the older record. For other tables, we do an update and if that hits no records we do an insert -- but then you have to deal with potential concurrent insertions (two threads both do the update and both get zero rows so both of them then try to insert a new record... which you may have to then detect and fix if there's no constraint violation on the inserts). So many fun possibilities 🙂
Deleting and inserting is also much-less-efficient than an update query
as a rule of thumb it's better to do an upsert rather than delete-insert I guess
(we have totally different timezones so responding in delay 🙂)
Correctness outweighs efficiency. Again, the choice of approach depends on the exact problem and the trade offs that are appropriate.
Can someone help me understand why this evaluates to false
.
(let [a 100] (list? `(:or ~a)))
while this evaluates to true
(list? '(:or 100))
and this evaluates to true as well.
(= '(:or 100) (let [a 100] `(:or ~a)))
=
is value-based in Clojure so, for example (= [:a 100] (list :a 100))
produces true
even tho' we're comparing a vector and a list.
list?
itself tests whether its argument is an instance of a specific type: IPersistentList
user=> (source list?)
(defn list?
"Returns true if x implements IPersistentList"
{:added "1.0"
:static true}
[x] (instance? clojure.lang.IPersistentList x))
so backquote returns a vector?
user=> (type `(:or 100))
clojure.lang.Cons
user=> (type '(:or 100))
clojure.lang.PersistentList
it prints with parenthesis not with brackets.
why is a Cons not a list? Should I be as confused as I am?
user=> (ancestors clojure.lang.Cons)
#{clojure.lang.ISeq clojure.lang.Sequential .Serializable clojure.lang.IPersistentCollection clojure.lang.ASeq java.lang.Iterable clojure.lang.IObj clojure.lang.Seqable java.util.Collection java.lang.Object clojure.lang.Obj clojure.lang.IHashEq java.util.List clojure.lang.IMeta}
Cons is a lot of things -- including an IPersistentCollection
but not an IPersistentList
Backquote is a special construct, most often used with macros.
user=> (macroexpand '`(:or 100))
(clojure.core/seq (clojure.core/concat (clojure.core/list :or) (clojure.core/list 100)))
user=> (macroexpand '(:or 100))
(:or 100)
This might help explain some of the "punctuation" you'll see in Clojure https://clojure.org/guides/weird_characters
which part of the punctuation link are you referring to? And why do we have to different list-like structures which print the same and both look like lists but are not both lists?
clojure-rte.core> (let [a 100] `(:or ~a))
(:or 100)
clojure-rte.core> '(:or 100)
(:or 100)
clojure-rte.core>
They print exactly the same.That page describes what single quote and backquote (syntax quote) do.
Printing data structures is "lossy" -- partly because data structures have to be realized in order to display them as characters. So a lazy seq and a cons will both get realized and printed as "lists".
Yes thanks for the link. The backquote is familiar to me. and the page says that parentheses denote "List"s.
Even more bizarre:
clojure-rte.core> (type `(:or))
clojure.lang.PersistentList
clojure-rte.core> (type (let [a 100] `(:or ~a)))
clojure.lang.Cons
clojure-rte.core>
type is showing you a concrete type, but the abstractions that type implements are the more important part (which you're not seeing)
clojure-rte.core> (rte-list? (let [a 100] `(:or ~a)))
false
clojure-rte.core> (= 'clojure.lang.Cons (type (let [a 100] `(:or ~a))))
false
clojure-rte.core> (type (let [a 100] `(:or ~a)))
clojure.lang.Cons
clojure-rte.core>
can I test for list or Cons?lists are IPersistentList, and more generally seqs (ISeq) are logical lists, so even more abstract. all lists are seqs, not all seqs are lists
why does this return false?
(= 'clojure.lang.Cons (type (let [a 100] `(:or ~a))))
because 'clojure.lang.Cons is a symbol but type returns a Class instance
user=> (= clojure.lang.Cons (type (let [a 100] `(:or ~a))))
true
but as a caution, it's never a safe thing to compare class instances for equality - the jvm uses a hierarchy of classloaders and class instances are unique per classloader
and classes loaded in different classloaders are not =
I need a scotch. now 🙂 Thanks for helping me understand. It is really surprising to a lisper that `(something something) does not return a list :-[
it does return a list
it doesn't return a list according to the list?
function
I think for the question you're asking, seq?
is actually more appropriate
user=> (seq? (let [a 100] `(:or ~a)))
true
it does return something that answers to car and cdr though. its a seq which has first
and next
seqs are logical lists (a list abstraction). lists in Clojure are specifically persistent list collections, which is a narrower scope
but [1 2 3]
also has a first
and rest
it doesn't actually
first and rest take a seqable and coerce them to a seq
clojure-rte.core> (first [1 2])
1
clojure-rte.core> (rest [1 2])
(2)
clojure-rte.core>
vectors are seqable and coerced to a vector seq before the operation is applied
so vectors don't "have" a first and rest, they can produce a seq view which does
(as do maps, sets, etc)
concrete lists directly satisfy the logical list abstraction
So is the list?
function simply poorly documented?
or poorly named?
no, it's very accurately documented
the gap here is in your prior knowledge of lists where list means something different
(I'm not saying you're wrong to be clear, I'm saying Clojure defines things in a subtly different way)
Alex, you said a minute ago that (something something)
returns a list, but it is list for which list?
returns false. So it appears that either the function has a bug, or is misnamed.
its ok for there to be bugs. the world is full of bugs. We just need to understand them and move on with creating beautiful programs.
@jimka.issy, there's a difference between a clojure PersistentList
and a sequence, which is commonly also called a list.
Most of the time, when you're thinking of a "list", what you really want is a sequence.
A clojure list is a specific type of sequence.
yeah, seq?
is a much more interesting predicate than list?
is
there are two levels of "list" here, and Clojurists often talk about them ambiguously
@ordoflammae I think the list?
is misnamed. it does not check for whether somethign is a list, rather it checks for whether something is a clojure.lang.IPersistentList
seqs are logical list abstractions, lists are persistent list collections
@jimka.issy,that's exactly what it's supposed to do.
both are often referred to generically as "list"
and both print the same
In technical terms, what you are thinking of is a sequence, but we just call it a list in every-day speech.
regardless of the ontological questions of what is or isn't a "list", pragmatically speaking the predicate people usually need is seq?
the list?
predicate is specifically asking about the narrower persistent list collection, not the broader seq logical list
Am I the first person to be confused about this?\
I doubt it :)
it's a recurring topic from the #clojure IRC :D
XD, I was confused about it when I started learning clojure; no sweat.
if you haven't seen https://clojure.org/reference/lisps, it sounds like it might help
So I'm defining a DSL where the user will type in a ???list??? like the following (:* a b (:cat (:+ d e) (:+ (:or a b))))
So does my parser for this need to check for list or sequence to distinguish leaf nodes from tree nodes?
I would use seq?
(or even more generically sequential?
or coll?
depending on whether vectors or sets etc are allowed)
the order is critically important so I'd say that I don't allow sets
coll? would work with that input - but use sequential
if you don't allow sets
if scope is what you have there, I'd use seq?
are sets coll?
my liberally regulary uses `(this and ~that) during the descent
is a set a seq?
as I said above, vectors, maps, and sets are not seqs, but they are seqable (can produce a seq view by calling seq
on them)
no, doesn't seem to be
Looking at my code, the thing that I'm assuming about the data structure is that I can destructure it with [first & rest]
and I can build it with back-quote, paren, and @
Hum, to distinguish leaf from tree, you can also check for emtpyness or nil depending on your use of rest or next
calling rest on :or would blow up though
and :or is a leaf
(:or x y z)
is not a leaf because it is a ???list??? whose first element is in the syntax of my dsl. However (or x y z)
would be a leaf because it doesn't match anything my parser is looking for. I would thus assume that (or x y z)
would be something the user thinks is compatible with isa?
, and if not, it's not my fault, it's a user error.
@jimka.issy oh I must have misunderstood - usually when walking nested lists the collections are branches and non-collections are leaves
if (:or x y z)
isn't a leaf though, that means :or
itself is right?
:or
a syntax element in the DSL. it indicates which functions handle the x, y, and z depending on the operation we are performing. So the question of whether :or is a leaf never comes up.
From memory, list?
is the predicate for things constructed with the constructor list
if that's true, then it really does make sense.
But, because you also have Vectors, and Java ArrayList and LinkedList and all these other kind of conceptual list like things, though not the things created by the list function
I'm not sure whether it is a good idea or bad to allow the user to use other sequences for the dsl. for example should I treat (:or x (:and y z))
the same as [:or x [:and y z]]
or even allow to mix and match? And if I want to disallow it, how would I?
list? does not check the first because it fails on something generated by backquote/tilde.
yes, that was the beginning of the conversation.
(let [a 100] `(:or ~a))
list? returns false on that
normal quote returns a list? and backquote sometimes returns a list? but not always
Thanks everyone for the help. I'm quitting for the day. will start again tomorrow morning
in confinement in France
I don't think you can easily distinguish the two. Because seq? allows more than just what backquote might return. I don't know there is a supertype of just what backquote returns + list?
I think it's a mistake to think of ' or ` as "returning" anything - these are syntax interpreted by the reader
you can use both of them on any data type. what that means, depends.
the fact that you're using quoting here should be irrelevant - define the syntax you want in terms of Clojure data
Hum, ya I guess that can make sense. Not to say that if backquote say on () returned a list?, his problem would be solved. but obviously, it does not. So he might be better of coercing things himself.
don't coerce, just use the right predicate for what you are checking for
using list?
also means that you break everything if you preprocess your data with standard collection functions like map
Say you wanted to allow only things returned from backquote over a () and lists? , but not vector? ArrayList, etc.
vectors aren't seqs
Ah ya ok, I think I often get seq? and seqable? and sequential? mixed up as to what is which
user=> (seq? [])
false
what people think are "lists" generically are seqs
Hi, I'm have some problems when do a minus operation with doubles values like:
(- 10.52 10.42)
I'm get a number 0.09999999999999964
.
Someone can explain why, and how to fix it?
that's just doubles being doubles isn't it?
you can ask for rounding with a specific precision iirc
I see now, i was thinking this was a clojure error, but I test in others languages and I'm getting the same result
Here is a link to part of Clojure equality guide, that has a link to a widely referenced article on floating point representations and why they are approximations: https://clojure.org/guides/equality#_floating_point_numbers_are_usually_approximations
the answer btw is if possible use ratios, if not use BigDecimal user=> (- 1/3 2/3) -1/3 https://docs.oracle.com/javase/7/docs/api/java/math/BigDecimal.html
@luis.geniole There are 9,602 members in this channel 🙂
Feel free to ask Clojure-related (beginner) questions here but it's not a water-cooler for general chat.
You can't get accurate numbers of the online members of a channel, just total.
Much depends on whether folks have Slack set to show them "away" after some idle time, as well.
Feel free to ask questions about Slack itself in #slack-help
is it possible to have a multimethod for multiple dispatch values?
like (defmethod X [:foo :bar] ...)
that catches both :foo
and :bar
values?
and there are some helper macros in various utility libs that get rid of the boilerplate for that
https://github.com/igrishaev/etaoin/blob/master/src/etaoin/util.clj#L15-L20 is an example
as you can see, there's not much to it
cool, thank you