This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2016-07-20
Channels
- # aleph (2)
- # boot (18)
- # cider (3)
- # cljs-dev (14)
- # cljsrn (28)
- # clojure (428)
- # clojure-austin (3)
- # clojure-hk (1)
- # clojure-ireland (5)
- # clojure-mexico (1)
- # clojure-quebec (2)
- # clojure-russia (49)
- # clojure-spec (138)
- # clojure-uk (45)
- # clojurescript (70)
- # core-async (1)
- # cursive (8)
- # datomic (13)
- # defnpodcast (3)
- # devops (1)
- # editors (4)
- # events (1)
- # funcool (14)
- # hoplon (17)
- # jobs-rus (1)
- # luminus (5)
- # mount (51)
- # off-topic (21)
- # om (9)
- # om-next (8)
- # onyx (43)
- # planck (6)
- # re-frame (13)
- # reagent (18)
- # ring-swagger (1)
- # spacemacs (17)
- # untangled (18)
- # vim (13)
- # yada (21)
Hi! I would like to return the value of an expression if that value meets a predicate, otherwise I want to return a default value. Using a let
and an if
does the job:
(def cm [{:index 3} {:index 4}])
(let [v (-> cm last :index)]
(if (integer? v) v -1))
or I can use a separate function:
(defn exp-if [v pred x] (if (pred v) v x))
(exp-if (-> cm last :index) integer? -1)
but I wonder if there is a more elegant/concise way to do this?@alexmiller: is there a way to destructure all keys under a particular namespace under a single binding with the new ns key patch? Meaning I'd like to destructure by "groups" corresponding to kw namespace
I am turning config maps (multi level) schemas into clj.specs, making more use of namespaced keys and flattening the maps as a result, and often these namespaces correspond to a components options, so I'd end up having to (partial group-by (comp namespace key)) before feeding them to the components constructors.
I'd imagine something like this: (let [{:ns [a]} {:a/foo 1 :a/bar 2 :b/foo 3 :b/bar 4}] a) -> {:a/foo 1 :a/bar 2}}
hi i have a empty? check, but possible values could also be long or keyword.. i wanna filter out all #{} [] "" nil
@andreas-thoelke take a look at fnil
Thanks @gon, I looked into fnil
but can't see how I can use it here, as predicates return true/false and I think I would still need a let
binding.
One idea: (some-fn #{#{} [] ""} nil?)
(remove (some-fn #{#{} [] ""} nil?) [#{} [] "" nil 1 :a])
Hello all, I'm using clojure-mail to read an email message, is there any way to download the attachement?
@mpenet that doesn't exist but you can :ns/keys [foo bar]
Or you can partition-by namespace instead of destructuring
@tab that may work.. but... anything nice maybe?
i could also use multimethod to validate... which probably would be nicer.. but still is there nothing more concise and easy in the core?
im not sure why empty? throws exception on Long and keywords.. whats the reason behind it? empty? in my opinion should be just true/false ...
:keyword and 123455 is clearly not an empty value
i could also make ugly code and catch exceptions from empty? and if its long or keyword just pass
but again its ugly and doesnt feel that functional...
its not the lack of options to solve it.. its about nice and clean code.. and it doesnt make sense that empty? throws and exception, since Long and Keyword is a value and clearly not empty
and if there is another core function which solves the problem? (since i dont know the reasons behind why you would throw that exceptions, most liley implementation details)
i cant tell from implementation of empty?
but i guess at that time there was no multi-method available, thats why its that incomplete
the biggest reason why you use a lisp like clojure is readability.. and from empty? i would believe everyone expects empty datastructure OR empty value of any form
peterromfeld: "empty?" to me is a nonsensical question on non-collections
it's an "I don't accept the premises of the question" sort of situation
I suppose you could phrase the question as either "is this an empty collection?" or "is this collection empty?"
empty? = true = #{} [] "" nil '() {} ...
these are all empty values nvm data-structure or format
(empty? input)
= is that input empty?
as you pointed out.. even looking at source.. the seq is the problem... 1234 is still sequential in my opinion.. its [1 2 3 4] keyword is a bit more difficult :keyword is kinda sequential from the perspective that it has a collection of chars in the end.. but [: k e y w o r d] is kinda weird
but then again.. as long its at least a sequence of chars.. it should be sequential!
for everything else you check the type
im afraid that i have to make my own multimethod to replace empty?
and eventually do the same for seq
.. i just cant understand why i have to do it and its not part of the core
empty?
takes a coll. if you pass it something that’s not a coll, then you should not expect good things to happen. In the future, there may be a spec that would tell you about this at dev time with instrumentation.
same with seq
. You might find the new seqable?
predicate helpful.
would you expect sensible things to happen with (+ 1 “a”)
(if so, you may be using JavaScript :)
if you back up to your actual problem, maybe there is some better solution. in general, I’d say it’s pretty weird to be in a situation where you would be trying to call empty?
on something that’s not a coll.
im importing a csv, and translating it to datomic datastructure, since input of this csv is not trustable i need to validate most of the input
sometimes it ends up that i have and attr with empty value
which could be nil or empty coll or just empty string ""
i want to remove them before i make my transaction
i could push responsibility up and ask programm to only do attr val if there is an actual val
but thats much more complicated then just filter all empty vals
its not a problem of solving it.. like i said i can use my own multimethod or i can have some catch exceptions
or complicate the actual functions
its still that i would expect from empty? to only return true/false.. and its true if the provided value is empty
i love lisp/clojure because of readability... and empty?
is missleading!
for my background, i have 0 java knowledge and whenever i need to java interop ive kinda a hard time... ive 0 javascript background and same with clojurescript.. whenever i need interop ive a hard time (got much better now).. i started with python, continued with elixir (still love that one) and are now active developer with clojure
and i love clojure because if you do naming correct, everyone can pick it up in few days
thats why have that logical issue with empty?
(empty? value)
@peterromfeld: personally I like the behavior of empty?
. I'd like to know earlier rather than later if I'm passing something other than a collection where I'm expecting one. If you want the behavior you describe, you could do something like (fn [x] (if (seqable? x) (empty? x) false))
again i can rewrite empty? with my own implementation and multimethod which is much cleaner and more readable
why would you expect empty? to throw and exception if you pass a long or keyword?
whats the rationale behind it?
and why would it work on "" then?
I definitely think longs should not be treated natively as seqs. You suggest breaking them up by number, what what if the long is represented in a different base? It would have a completely different seq representation.
well (seq "asdf") => (\a \s \d \f)
why (seq 1234) not=> (\1 \2 \3 \4) ?
its all chars in the end
why not?
its chars
16 = 16 in base 10. 16 = 10 as hexadecimal
which one should it be?
in this case just char sequence
because i dont treat it as a number
i dont care if hex or whatever in this case
thats not how i ask it to behave
i dont ask it to be a number
or hex or whatever
i just want to know if its something
whatever it is
you have enough math functions to validate your numbers
but in this case you dont care what the type is
you just want to know if it has a value
is the value empty? or not?
and from my logic at least 1234
is not an empty value
same goes for :keyword
now empty is tricky, because of these different types
thats why #{}
or []
is empty
which works fine for most of the data types, like:
same for ""
the issue is that there is no empty for keyword or long
and thats why you need multimethod
if you have a long or keyword.. there naturally is a value, because of course this value is what defines it to be a Long or Keyword
but im sure the time empty?
got implemented, was before there was multimethod in clojure core
On clojure 1.8 - what's the best way to test for seqable?
there is a seqable?
impl in core.incubator
@peterromfeld the functions in core have expected input domains. the general approach is that that input domain is often not checked by the code and you may see exceptions or other confusing behavior if you violate expectations. you are not going to see these functions (now or ever) attempting to catch all possible input cases and coerce them to meaningful behavior. you may see (now that we have spec) the ability to catch those erroneous inputs earlier via instrumentation.
empty?
is doc’ed to work on coll
, which (in core) means collections, which includes seqables (like strings)
it makes no sense for a number to be seqable
in the end, I think you will be more productive in trying to understand and internalize some of the design, rather than continuing with a mental model that is inaccurate and wishing it were so
some good resources: http://clojure.org/guides/faq http://insideclojure.org/2015/01/02/sequences/ http://insideclojure.org/2016/03/16/collections/
in your actual use case it seems that you have a variety of conditions that make an attribute “skippable” - those are specific to your problem and I think you should make a function for it. Then use standard functions to find and remove skippable attributes.
thanks ill go through that, i still think for current problem its easiest to just make my own whatevery-empty?
multimethod and be done with it
I’d recommend using or
over a multimethod
im sorry i could not bring myself right now to read all of it, its just started explaining what the different datastructures are
no worries
late here right now
about to go to sleep
or i was thinking of, but well i could add a not to make the or work
oh no
the issue was that or to cancel execution would return a true where i would want a false
not sure fuck, time to sleep and look tomorrow
but still if i do (filter #(when-not (or (keyword? %) (number?)) (empty? %)) stuff)
its super ugly
and kinda difficult to read when you come back a year later
#(when-not (or (keyword? %) (number?)) (empty? %))
is a function - make it one and give it a name like valid-attr?
(filter valid-attr? stuff)
is very readable
there many versions to solve it, im still not convinced by the examples i got, why empty?
behaves the way it does
(empty? val)
look at it from logical perspective without any background to clojure or programming
functions are defined over a domain of inputs. passing something outside that domain is a bug in your program.
whatever
ill just hack my way
like you can always control the input
well you’re writing the code, so … you can
it was just a logical observation of the naming empty?
and what i think many people not that close to how clojure works, would interpret it
empty?
is logically a question you can ask of something that contains things. 5 does not contain things.
5 is a value
0 is a value
right, but not a collection of values
"a" is a collection of values?
as Clojure defines it, yes
strings are treated as collections of chars
yeah whatever
if thats the logical response..
whatever
123 is not a collection of chars?
it’s a number
its chars
1 2 3
no it’s really not
the Clojure reader reads Clojure source and produces Clojure data
123 is read as the number 123, not the string “123"
in my world every "shit-whatever" is a char
you can interpret differnt chars to different types
numbers or whatever
yes, and that’s different than Clojure data
but all thes types are a composition of chars
you need to deal with the fact that your “data” is all strings
either coerce to actual Clojure data, or deal with it as strings
you dont have the luxury to always have clojure datastructures as input
and even then it could get difficult to evaluate all of it
i have clojure map
with key vals
but sometimes i dont have vals or empty vals
and sometimes they are Long or keywords
neverming
we are circle
its just clash of perspectives
Seems that way
It was an interesting exchange of perspectives, though. Wish I had popcorn.
data coercion is an inherent part of your problem domain
Clojure does not magically solve that
it DOES
i can just make my own multimethod or function to replace empty? to behave the way i expect it to
@peterromfeld: (->> yr-map (map (fn [[k v]] [k (str v)])) (into {}))
now all your vals are strings !
thanks alex, you gave at least quite much more explanations 😛
i guess there could be things changed underlying to it
if your input is strings, you need to supply some interpretation of those strings. csv is inherently poor at this. there is no way to distinguish the string “123” and a number 123 as CSV has no explicit schema. Or false / “false” or nil / “”. It is not fair to push that interpretation (which is specific to your problem) into core functions.
no ive a map of clojure datastructure
its just most attrs have good values
but some have shit which i wanna filter
“good” implies interpretation - and that’s up to you
empty?.. #{} "" nil []
to make the underlying stuff work in a different way to get to same result, it requires so many more lines or maybe i just do it complete wrong
whatever
i have not heard a solid explanation why (empty? 123)
should throw an exception
same for (empty? :key)
omg, for the third time: functions are defined for a domain of inputs and those values are outside the domain.
its a fucking function with a name
im not in java here
with objects and shit
or maybe i am
why doesn’t + work on keywords and numbers?
why doesn’t assoc work with strings?
because + has a very strong meaning
its for numbers
ALL of these have a strong meaning
back to naming..,.
it’s in the docstring
Definition of empty?
:
(defn empty?
"Returns true if coll has no items - same as (not (seq coll)).
Please use the idiom (seq x) rather than (not (empty? x))"
{:added "1.0"
:static true}
[coll] (not (seq coll)))
It's that way because it's defined that way.why is a sting a coll?
123
and :key
aren't collections (as defined by the language), so, it throws an exception
that is not an accidental choice of words - arg names have a specific meaning in core docstrings
a string is seqable (can provide a seq) of chars
its a sequence of chars
this is documented on the sequences page http://clojure.org/reference/sequences
[]
is a sequence of chars, too
an empt one
but it has two chars
its vector, empty one
"[]"
<- is a string as defined by the language []
is an empty vector as defined by the language
"[]" is different to []
the point is type matters in clojure
one is a sting with a value
the other one is empty vector
thats also my point
[] = empty vector
"" = empty sting
nil = empty whatever (nothing)
#{} = empty set
123 = not empty
:key = not empty
on the last two, I would say you are asking an invalid question
no the value is it empty or not
its not
there is a value
vectors, strings, and sets are all collections, so they can have the property of "emptyness". 123 is a literal and so can't be empty (as a side note, how would you write an empty literal?), :key is a keyword/function and also doesn't have the property of "emptyness"
that’s not what empty?
says it does
there is no empty Long or Keyword
if there is a value (which there is by just being one of these types) its not empty anymore
>Returns true if coll has no items Actually, that's exactly what empty says it does. Since 123 and :key aren't collections, they are undefined for this function and thus, you get a traceback.
the way "string" is different to 1235 is just implementation detail
from logic its still just a sequence of chars.. both
They’re displayed as a sequence of characters. Underneath the hood, they’re handled differently.
implementation detail
no, just no
this is at the foundation of Clojure/Lisp. the reader converts your code (characters) into data, that can be manipulated by your program.
so what would be your harm, if empty?
would say false on Long and Keyword?
fuck that specific implementation details
its a LISP
and its about meaningful NAMES
I give up
i can work around it.. like i said.. its just a naming i just cant agree.. and you have not given me so far a valid logical explanation why you would do that..
its just excuses
thanks for the core.incubator tip alexmiller
i understand underlying implementation complications and why you may would differntiate these things from implementation detail view
but from a non professional view, just about naming and general logic
one man’s excuses are another team’s 10 years of design efforts
i cant understand it
yes i know
its a or
with nil? and seq
and i believe it was done before multimethods
that has nothing to do with it
if it was defined now, it would be defined the same
(defn empty?
"Returns true if coll has no items - same as (not (seq coll)).
Please use the idiom (seq x) rather than (not (empty? x))"
{:added "1.0"
:static true}
[coll] (not (seq coll)))
(defn ^boolean empty?
"Returns true if coll has no items - same as (not (seq coll)).
Please use the idiom (seq x) rather than (not (empty? x))"
[coll] (or (nil? coll)
(not (seq coll))))
im not so sure about that
from a outstanding eye, without any clojure knowledge but just common sense and logic
it doesnt make sense
that’s not the current definition https://github.com/clojure/clojure/blob/master/src/clj/clojure/core.clj#L6087-L6092
@peterromfeld: where did you get that code from
the code @scriptor posted is the code, and has been since at least 2008
oh no just : CLOJURE_VERSION=1.7.0
it still doesnt change things lol
this one or is useless
its unessacary code
(nil? x) == (not (seq x)) for most of the time
there may be perf reasons for it in cljs
of course left only works on nil 😉
@alexmiller: possibly, but cljs's seq
already has a check for (when-not (nil? coll)) http://cljs.github.io/api/cljs.core/seq
(def
^{:arglists '(^clojure.lang.ISeq [coll])
:doc "Returns a seq on the collection. If the collection is
empty, returns nil. (seq nil) returns nil. seq also works on
Strings, native Java arrays (of reference types) and any objects
that implement Iterable. Note that seqs cache values, thus seq
should not be used on any Iterable whose iterator repeatedly
returns the same mutable object."
:tag clojure.lang.ISeq
:added "1.0"
:static true}
seq (fn ^:static seq ^clojure.lang.ISeq [coll] (. clojure.lang.RT (seq coll))))
it does what it says
its still naming
why is (empty? "")
working but not with Long or Keyword... yes seq
says exactly why.. but its still naming clash for me
i dont have the object java background, so i only understand seq
works on char sequence, but be careful not works on charsequence that starts with : or is only numerical
those are not char sequences
they are numbers and keywords
what is a character? what is a sequence?
every fucking symbol is a character
if its a a
or a 1
or a :
its characters
no, they are not once the reader has read them
thats why you have datastructure and types
so you dont have to fuck around with random char sequences
some of them have higher meaning
@peterromfeld: your argumentative communication is really off-putting when people are being so patient with you
you have a fundamental misunderstanding here about how Clojure works
the Clojure reader reads source (characters) into Clojure data. At that point :foo
is not a string, it is a keyword
5
is not a character or a string, it is a number
it makes sense that (seq "foo") returns a sequence of characters, it does not make sense that (seq 1234) returns a sequence of digits
The reader page above defines how that is done
all Clojure functions take and return Clojure data
not strings
1234 is still a sequence of single digits put together
when written in a file or typed into a repl yes
but then the reader reads it as an atomic number
010 evaluates to 8, should it be "010" or "8"? your interpretation simply doesn't make any sense
2r010101
is another representation, also read as a number
we are using a high level language which should abstract most shit, to down that deep?
well i can do quite much without this "basic programming"
by using high level abstraction langs
i never thought about theses things in other languages before
because i did not have that level of readability
in any other language i just go with it, wtf thats how it is
I’m trying to figure out if it’s possible to specify in clojure.spec that some function has an equivalent other implementation that should return the same values given the same inputs. I’m building 2 implementations of a protocol that I would like to check against each other.
@joost-diepenmaat: that is a good and wise question, which may some day be provided within spec
Or should I use some mix of clojure.spec and test.check if I want to do that?
@peterromfeld: it seems like you're either having a severe misunderstanding of how abstractions should work or you're just inexperienced, either way what you're saying doesn't make sense. I'd suggest trusting ever language designer ever to be right on this one.
thanks @alexmiller 😄 I guess that means I should read up on test.check then 🙂
@joost-diepenmaat: (s/fdef fname :fn #(= (:ret %) (apply other-fn (:args %))))
should work I think?
I’ll give it a shot @codonnell
im a bit inexpirienced, the thing i love most about clojure is maintainablity as long as you get naming right (and how easy to teach new employees if naming is good)
so even if you dont know that much about programming, you can get started quick in clojure with good names
logical names
names that make sense even without knowing about implementation details
I’d suggest that the names we’ve been talking about are good names and that your semantic mismatch is due to a misunderstanding of how Clojure works, as far as I can tell
this isn't a clojure thing, most sensible languages view strings as something that can be turned into a sequence, and longs as atomic values that cannot
defined input sets are not implementation details. they're part of the definition of a function. empty?
is defined and documented to work on collections, which numbers are not
what you consider an "implementation detail" is what others would consider an expected convention
i still cant understand how string is a collection and numbers not
and most programmers would be confused if (seq 1234) somehow turned it into a sequence of digits
ok then im just to unexperienced
its just the logic that this 12345 and "asdf" is both a seq of chars for me here visual and logical
there are languages that have tried to coerce numbers as digit-sequences, typically this has not worked out well
because the vast majority of the time we don't want to use 1234 as a list of '(1 2 3 4)
"
"
just visualises a string for me
i neither want to
i just wanna check if there is a value of meaning
i dont wanna transact a empty attribute
ya need to figure out different, or make my own valid? instead of empty?
maybe call it not-seq? insead of empty?
would welcome it
if a given value is empty
but given value can also be Long or Keyword
@joost-diepenmaat: seems to work here:
=> (defn my+ [x y] (+ x y))
=> (s/fdef my+ :args (s/tuple number? number?) :fn #(= (:ret %) (apply + (:args %))))
=> (stest/check `my+)
({:spec #object[clojure.spec$fspec_impl$reify__13789 0x3523619d "clojure.spec$fspec_impl$reify__13789@3523619d"], :clojure.spec.test.check/ret {:result true, :num-tests 1000, :seed 1469028616727}, :sym user/my+})
have you encountered a point in your code where you've needed to treat certain longs or keywords as empty?
but it doesnt
it throws
Because empty?
isn’t meant to be used on non-collections and keywords and longs aren’t collections. It’s a misuse of the function.
i dont need to treat them by themself as empty, but i have a map with eventual empty vals, and wanna remove the attrs with empty vals
@peterromfeld: if you ever end up calling empty? on a keyword or long, chances are there is a bug somewhere in your code
meaning, where your code is expecting a collection it's getting one of those instead
@peterromfeld: you can define your own, say, IValid
protocol with a (valid? [x])
method and implement that for all the types you care about
@codonnell thanks, that looks usable. I need to refactor a few things in order to make that work with the protocols involved
yeah i know i can my own multimehtod
or protocol
its just the general meaning of empty?
if you dont think too depp into the language or others, what would a little kid understand by a function called empty?
i know how to fic my issue
if you consider ZF set-theoretic representation of natural numbers, then the concept of an empty number does makes sense
its really just about the naming for empty?
but that's not clojures representation, so it doesn't make sense in clojure
I think empty inherently involves the notion of containment based on its English definition
and that seems like an exact match to what empty? means in Clojure
would a little kid understand the question “is the 5 empty?"
that is a nonsensical question
(empty? val)
ok ill stop sorry
i guess ill do (not-value? val)
and it will be true if its an empty datastructure or empty sting or nil
i like to make use of nil if something is not true or no return value, of course you still wanna throw on unexpected behaviour.. but making use of nil and sometimes you have empty datasets depending on fucntion, and then you go ove the whole data and remove the empty shit looked very convenient, just have to replace empty? with my not-value?
It's hard for me to imagine a situation where you would want to treat an empty string the same way as nil
@dg: I consume an api that sometimes returns an empty string instead of null to indicate null values. I won't argue that it's good practice, but it's not an unimaginable situation.
Yikes. But you're right, I was assuming @peterromfeld had control over his api
can tree-seq navigate a map of vectors of maps of vectors etc..?
it can navigate anything if you tell it how to
(tree-seq coll? seq ...) works pretty good in a lot of cases
Why do
(deftype Foo [] Object (toString [this] "Foo"))
and (deftype Foo [])
(extend-type Foo Object (toString [this] "Foo”))
produce different behavior? The first version works as expected (str (Foo.)) => "Foo"
while the second throws IllegalArgumentException class java.lang.Object is not a protocol clojure.core/extend (core_deftype.clj:769)
According to the docstrings, deftype
works with protocols or interfaces or Object
, whereas extend-type
(via extend
) only works with protocols.
Is there any way to change the str
representation of a type after it has been created, or do you absolutely have to do it in the deftype
?
Hi all, i want to uberjar and aot and then run all tests. I'm calling (clojure.test/run-tests testedns) in main, but it only prints deftest titles and does not run tests.
@radon no - the class underlying the type has been created with the method in it already (that’s why you can’t change it later). Of course you could have the impl in deftype call a function that you redefine later.
@nicola uberjars don’t typically include the tests afaik?
I would run tests before making an uberjar—after all, what are you going to do with an uberjar whose code doesn’t work?
What’s the easiest way to remove the namespace from all keyword keys in a map? (think map used w/ spec but now need to serialize w/o namespaced keywords)
Just make your deployment pipeline something like lein test && lein uberjar && <deploy>
.
Surely you won’t be deploying so often that the 5-second startup of lein
would be an issue?
Tests are for development, and you would not include development code in the production build.
newbie question, is there a way to get a symbol
from a var
? Some sort of unresolve
?
Well, you could just stick uberjar
onto the end. That would eliminate the duplicate lein
startup time.
self-answer by looking at the source, I can use .sym
and .ns
, akin to this https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Var.java#L130
(symbol (str (.ns v) "/" (.sym v)))
repl is power 😄
@radon (when load-test ....) everywhere in clojure.test, i think lein set it to false while uberjar
^ integration tests are run after build
Right, but I would guess that integration tests would not be run from within lein test
?
In that case, I guess you should separate the unit and integration tests (I think clojure.test
has support for enabling/disabling labeled groups of tests)…
I found problem, aot'ed namespaces are lazy so (all-ns) is empty. If i require test namespaces everything works
I'm looking for some help figuring out what's going on with a 4Clojure problem (#150, palindromic numbers). My solution works fine on my machine, and the longest test case completes in around 55 ms, with all cases together taking around 140 ms. I know that 4Clojure is running on a fairly ancient version of clojure. Is there a behavior change to, e.g., laziness that would greatly change the performance characteristics of my solution? Or is the timeout really shorter than 55 ms? My solution attempt is at https://www.refheap.com/121787 - I get the same timeout on tryclj.