This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2015-09-24
Channels
- # admin-announcements (17)
- # alda (5)
- # aws (4)
- # beginners (19)
- # boot (80)
- # bristol-clojurians (3)
- # cider (15)
- # clojure (257)
- # clojure-berlin (1)
- # clojure-czech (1)
- # clojure-indonesia (1)
- # clojure-nl (1)
- # clojure-poland (1)
- # clojure-russia (77)
- # clojurescript (186)
- # core-async (7)
- # core-typed (6)
- # cursive (8)
- # datomic (2)
- # devcards (2)
- # editors (45)
- # emacs (23)
- # hoplon (83)
- # jobs (1)
- # ldnclj (106)
- # leiningen (43)
- # off-topic (4)
- # onyx (31)
- # reagent (10)
- # yada (1)
Hello guys, I am new at learning Clojure. Could someone explain me the term "not-nil?" and difference between "not-nil?" and "not"?
Does not-nil?
even exist?
You could easily write one: nil?
is a function which returns true if the argument is nil. complement
is a function which takes a function and gives you a new function whose truth value is opposite.
So (complement even?)
would give you a function identical to odd?
By the same token, (complement nil?)
gives you a not-nil?
.
(nil? nil)
=> true; ((complement nil?) nil)
=> false.
I don't know if this is actually helpful.
BTW, I have a different question... say I have a function user/update!
, which updates the supplied user in the database. Is it more helpful to return the user on success and nil
on failure, or return the native response (rows updated), or return true/false
...? Or is it really just a matter of how I feel?
(compliment <@U08B448C9>) ; why thank you
Or more likely, @amacdougall is not an atom
@amacdougall: I’d go with user on success and false on failure.
@harshdeep, I got a lot out of The Joy of Clojure.
There are other Clojure books and sites! But I learned everything I know by reading that book and then just experimenting a lot and reading code on other people's projects. Of course, I don't know all that much yet!
Thanks, @akiva.
Yep! That's because nil?
is in clojure.core, the set of basic functions available in every namespace. Check out http://conj.io for a useful listing of stuff.
Remember, you have to evaluate each set of parentheses one at a time. (complement nil?)
gives you a function. ((complement nil?) nil)
gives you a function, then runs it with the argument nil
.
@harshdeep: ((complement nil?) nil)
Try this instead:
(defn not-nil? (complement nil?))
(not-nil? nil)
(not-nil? "hello!")
Wait, not defn
; use def
.
And yeah.
The complement
thing is for illustration; don't do it in real life!
complement
can be useful, just not for nil?
.
Just one more question, does Clojure have applications in the field of Artificial Intelligence?
Just totally throwing this out there but as a Lisp, it should be at least philosophically biased toward AI although it may not be as pure as an elder Lisp due to the JVM. I don’t see, however, how you couldn’t do anything in Clojure for AI that you couldn’t use Racket for, say.
And my understanding of AI is that although Lisp may have historically been an AI language, that's because its design matched the models of mind that 60s researchers were working with. Modern AI is very very different.
I have a feeling that your choice of language is not a strong factor in your success with AI-related projects these days.
Hi, prompt please analogue hibernate-envers on clojure, i will rewrite my project on clojure and i looking for alternatives. The goal is to have a story of entities, can view of deleted and the older versions
If you're interested in an object database with powerful history features, I think Datomic might be right up your alley, @sanitar4eg .
Never used it, but I understand that's what it's good for.
Unfortunately at this stage is not possible to change the database, it is common mysql
Well, something in Clojure might already do what you want, but I don't know enough of the ecosystem. Maybe someone else has some advice.
Bear in mind that you could always use the Java code directly! Clojure is good at interoperating with Java.
You could build a Clojure app around the Java ORM.
Just use some standard application architecture patterns to turn the ORM into a component that presents a pure Clojure interface. http://martinfowler.com/books/eaa.html is still a very worthwhile read, after all these years.
Its lessons apply to every language I've ever used.
Thanks for the advice, I will read it. My task allows to refuse ORM. Korma allows to quickly invent the envers, but maybe there are ready analogs
Well, the Martin Fowler book isn't about ORMs, although it mentions them. It is about application architecture in database-backed client-server enterprise applications, though, and it sounds like that's what you're doing now.
And I just got all my tests to pass. As usual, I was forgetting the argument order of <
and >
....
But I came up with a decent mnemonic. <
is like a small point growing, meaning the arguments should be in ascending order. >
is the other way around. Might save me from avoidable stupidity in the future.
some?
does what you would expect not-nil?
to do
@amacdougall: I think of the >
as a crocodile. It always bites the bigger number
Yeah, but in Clojure, that means it skips everything in its way and goes to the far right! 🐊
I don't know if I like using some?
as a not-nil and seq
as a not-empty. Brian Marick (I think) called them shibboleths, and I'd agree.
some?
is clearly the name of a function which tests a predicate against a collection, you know?
But every language has at least a few things where you just learn it, it becomes an "idiom", and eventually it seems weird to do it any other way.
For example, virtually every damn thing about Javascript.
(doc some?)
-------------------------
clojure.core/some?
([x])
Returns true if x is not nil, false otherwise.
(doc some)
-------------------------
clojure.core/some
([pred coll])
Returns the first logical true value of (pred x) for any x in coll,
else nil. One common idiom is to use a set as pred, for example
this will return :fred if :fred is in the sequence, otherwise nil:
(some #{:fred} coll)
Yeah, it's right there in the doc comment! I just mean that its name is a bit misleading. Maybe I'm just unfairly comparing it to some
in other languages. Array.some
in JS, Enumerable#any?
in Ruby.
@amacdougall: you’re not the only one who finds that name confusing
Anyway, it's not really a big deal. But yeah.
Anyway, time to get at least a little relaxation out of the evening. Wrote some more tests, life is fine.
or
is another one that you can use in ways that it loses it's meaning. For example you can replace this:
(if-let [x (do-something)]
x
(log-error)) ;returns nil
with:
(or (do-something)
(log-error))
Which to someone who isn't familiar with Clojure doesn't make quite as much senseI'm late to the party but off-the-cuff I would think that (complement complement)
would be the same as identity
@harshdeep: What kind of AI are you interested in doing with Clojure?
I'm doing a lot with L-systems and Cellular Automata here: https://github.com/decomplect/ion/blob/master/src/ion/ergo/core.cljc
And I do think the language makes a difference. I'm amazed at how much power and flexibility can be packed into so little clojure code.
How's this for a crazy function:
(defn produce
"Returns a lazy sequence of colls from a recursive, axiomatic, transducible
process."
[init-f prep-f seed-f get-xf]
(letfn [(process
[coll]
(lazy-seq
(when (seq coll)
(let [new-coll (into (init-f) (get-xf coll) (prep-f coll))]
(cons new-coll (process new-coll))))))]
(process (into (init-f) (seed-f)))))
@firthh putting side effects in an or
like that is pretty dirty 😈
@danielcompton: yeah I know it's not pure, but in that case the (do-something)
is also making a call out to the database.
@meow: I think it's pretty, but this is something I often struggle with internally with Clojure. I really love the language, and it's hard for me to judge because I haven't yet had the pleasure of writing any reasonably complex system with it, but if I were to just look at the signature of that function I would have a hell of a time figuring out what to do with it. How do I know the arity of init-f
and seed-f
should be 0 but prep-f
and get-xf
should be one? the arguments to pass is currently just lore of the library. I have to either read the source or just throw random arity functions at it until I stop getting exceptions thrown at me
I would also love to know/read about/get advice from others for if this doesn't become an issue in practice. I'm not convinced it actually is a real issue in practice, and if it is it can be solved with e.g. Schema.
does anyone have any experience with Sparkling here? Would they recommend it, esp. over Flambo? Or are all the cool kids forgoing Apache Spark for Onyx?
@socksy: I'm the initiator/maintainer of Sparkling: What do you need? I'm running jobs on a daily basis on Sparkling, and I know that the guys over at AppsFlyer were hosting a Spark/Sparkling-Meetup and you might want to check out https://dataissexy.wordpress.com/category/bigdata/
hey @chrisbetz I was just trying to work out whether it’s production ready and generally well used. We need to write some code reading from a Cassandra database, and were trying to evaluate our options
Hello Everyone, I'm using prismatic/schema, and sometimes even trivial things like (s/validate s/Str 1)
get validated. This should clearly throw an error, right?
Has anyone run into this behaviour before?
@samebchase: - I haven’t, but I mainly use it for validating complex nested maps/sequences. I do know that Schema can do conversions. I know nothing more other than it can - have you accidentally toggled the ‘convert’ flag?
@colin.yates: I don't think I have toggled that flag. I just started a fresh repl and tried the above snippet. The strange thing is that earlier in the day it worked fine, but now everything is getting validated.
there is a magic flag you can use to turn on validation, maybe you can disable it everywhere as well (I thought it was only for use in the macros…). Let me check...
I have used set-fn-validation!
before, but that is for functions defined using Schema's own defn
and not the vanilla Clojure defn
.
yeah, thought so. I am grabbing at straws - I don’t know then.
what does restarting the repl do?
@samebchase: a clean REPL and it does fail to validate for me
I just created a new project and tried and it works, but does not work in my existing project.
I guess the next step is to start ripping stuff out to get the smallest reproducible project then?
Hm. I've run into this before, will try some other stuff and see.
@socksy: saw you're using a german phone nr. are you in hamburg sometimes? i could give you an intro to spark/sparkling over lunch. Otherwise: yes, its production ready (for what I needed it for), it lacks dataframe support (in case you need it) or MLlib-support.
@chrisbetz: I’ve never been to Hamburg! I’m Berlin based. It may be interesting to pop around for a day? But I understand @pesterhazy (former colleague) and you did a talk a while ago, so maybe I’ll send him a message. I think though that we’ll implement a version in Spark and a version in Onyx this week, and see how they fare. Was just wondering the state of affairs since the previous code that Paulus had written was in flambo, but your stuff looked like it added improvements. If you say it’s production ready, we can probably just go ahead and write the prototype in sparkling rather than flambo (which I have used before for non-cassandra tasks)
@ian: Interesting questions. That produce
function is used internally in the ergo
library and isn't really meant to be part of the public API, so I'm not too bothered by it being a bit inscrutable. It is as abstract as it is so that it can support many variations of processes needed by formal grammar rewriting systems and cellular automata. At the same time I view it as a bit of a complement to the reduce
function, so this produce
function recursively produces new sequences applying transforming functions as necessary, so there is a bit of built-in complexity. But there is also simple unfamiliarity as this is the sort of thing that is typically handled in a one-off fashion in most code, rather that this uber-flexible beast of a function. But, like anything, one can become familiar with it.
And other functions can add sugar on top of it. For example, most rewriting systems use vectors for their collections, don't need to prepare the coll each time through the loop outside of the transducer stack, and have an axiom value built into the rewriting rules in their transducer stack. So I have this bit of sugar:
(def rewriting-system (partial produce #(vec nil) identity #(vec [::axiom])))
Now to use this rewriting-system
all you need to supply is get-xf
, a function that has an arity of one and is expecting to return a transducer.@chrisbetz: do you plan on adding support for SparkSQL/Dataframes to sparkling?
@ian: The short answer is that these issues are really design issues that are independent of Clojure the language. You can certainly build complex systems with Clojure that have simple and elegant APIs. You can also just as easily create a mess of tangled, confusing nonsense.
Hi all! I’ve got a quick question: I defined a macro that expands to code containing a private function call. As a result I can’t use the macro outside its proper namespace. Is there an idiomatic way to deal with this situation?
@ian How do you ever know the signature of a library function without reading documentation/source?
Here's how I've defined a cellular automata system using the produce
function:
(defn ca-system
[prep seed get-xf]
(cons (set seed) (produce #(set nil) prep #(set seed) get-xf)))
which reminds me, I still haven't dealt with grid boundary behavior for the CA stuff, so that might need to change. Actually, that's going to be handled in the transducer stack, so nevermind.
@socksy: Hi, make sure to try the improvements on testing broadcast-dependant code using @-sign-deref, if necessary. That's nice ;)
@borkdude: is this quarrel sparked by this blog from circleci? http://blog.circleci.com/why-were-no-longer-using-core-typed/
@agile_geek: seems so.
@borkdude: I haven’t used core.typed but I always had some concerns about typing as an afterthought to the language.
I get what Bodil means. Question is, does Clojure still give you more advantages over other languages that have static typing? If yes, continue with Clojure, if no then look elsewhere.
I’ve mainly worked with static typed languages and I don’t miss it but I don’t have enough experience of a large codebase being changed by many ppl to say either way. Ruby community seems to say just test more?
my experience with core.typed is that every time I try it, something was broken I haven't used it seriously in any project, but I think it's a matter of maturity
@agile_geek: I think that's how Uncle Bob spoke about it too: type checker is a form of testing, but usually not good enough to replace manually written tests
I know someone who prefers writing in Haskell, just because of the development experience, not because of some sense of safety
Well all type checking at compile time is static testing but I can’t say that it gives me enough confidence in my code not to write lots of tests in Java, for example, so having a dynamic typed language doesn’t cost me much more.
@borkdude: haven’t written in Haskell so ‘no comment’ but I here this glib ‘If it compiles it works’ quote a lot…don’t believe it unless Haskell uses amazing AI!
https://clojurians.slack.com/archives/clojure/p1443104629002264 It’s definitely not… but in the very limited Haskell experience I have you really can program in a different way with a strongly typed language…like composing a set of functions to do what you want while only declaring the types (and leaving the actual functions unimplemented), and the compiler being able to tell you something isn’t right just based on how the functions are typed/called. It’s a cool thing I had never experienced before
I suppose so, but to @agile_geek ’s comment about Java with regards to that… it’s just a way of writing code I have never seen someone do in Java.
@jeffh-fp: me neither!
Maybe it’s something more typical in statically typed functional languages? (preferring function composition, relying on pure functions more)
@jeffh-fp: I suspect you're right
@jeffh-fp: I always try to understand why people prefer or dislike certain languages. Well, probably you like Clojure else you wouldn't be here.
my two cents is that all of the complaints people have with dynamic typing I had with python, but for some reason I haven't had the same issues in Clojure. So far the only pitfalls I hit from time-to-time are 1) using map with side-effecting functions 2) getting a lazy seq when I wanted a value.
I'm currently dealing with an issue that a query from mysql returns a bigint instead of a long, so somewhere else Math/round (after dividing two of these) sees a BigInt and not a long and I get an Exception. Don't know if a type system could have prevented this.
@meow: Interesting point about produce
being a power tool with a learning curve. I think it's fair to take that view. After all, a big library of simple and focused functions has a learning curve, too.
My 2 cents: Some good points above WRT static vs dynamic. I don’t think its fair to lump static typing in java w/ Haskell. The type system in Haskell is tons more useful/expressive. Haskell type system does catch some garden variety errors, but the best part is that it makes that kind very easy to fix. “You passed an a instead of a map of a’s” and the like. I like dynamic typing fine in Clojure, but worst part is some error messages are harder when reworking things
Dynamic typing in e.g. Ruby/python/javascript feels a bit different because of the mutability. The value changes over time and can pick up attributes as it moves around in ad-hoc ways which can get pretty brittle
haha yeah. I think Bodil is hilarious. I don’t take some of those things too seriously
@danoyoung: Considering SparkSQL/Dataframes: I'm currently experimenting with it (for some other parts of the projects), so you might see some support for it, but not in the near future, or at least not from my side.
Is this normal? Clojure and memory https://gist.github.com/honza/bdaa08241e2a0fef0b32
@honza: https://github.com/technomancy/leiningen/blob/master/sample.project.clj#L264
pass args to the JVM to control memory allocation
@christianromney: and set it to what? 128mb?
depends on your actual usage. you should use a profiler like https://www.yourkit.com/ to understand your app’s actual needs.
i don’t recommend this for serious use, but you might also try the quick and dirty approach of throwing a number that “seems” reasonable to you
I'm getting boxed math warnings for the following function and I'm not sure where to put type hints to fix it:
(defn gen
"Returns a function that, when called, will call f with an incremented
generation number and an additional context argument."
[f]
(let [generation (volatile! -1)]
(fn
[data]
(vswap! generation inc)
(f @generation data))))
I've seen fixes like the following, but in my case I'm not saving the incremented value in a let
block, so I'm lost:
^long nn (vswap! nv #(inc ^long %))
of course you can
how do you think the first lisper did it -wink-
so many great resources available to the beginner now
JoC is great, but not for new-to-Clojure folks
Living Clojure by @gigasquid, Clojure for the Brave and True are two great starting points
http://www.purelyfunctional.tv/ has nice ‘casts you can buy if you’re into that
So Living Clojure, I feel is good. I am gonna download it, and go through it. Thanks
@meow: I didn't mean to say that it's a poorly written function or anything like that at all. It's just that to me in my naïveté, that seems like a function that could be a barrier of entry or re-entry for the code base for new or returning devs or users of the library. Perhaps it wouldn't have stood out to me even if there was example usage in the docstring or it written out in plain English. But that might be a nitpick. However it also might not be and I'm glad I brought it up anyway. :) thank you for your response.
@potetm: knowing the signature isn't necessarily helpful in this case, is my point. Let's say you see the signature of a function and it's something like (add-all-nums [nums])
. I think it's fair to say that just glancing at that information alone will make it rather obvious what that function expects as an argument. However (do-thing [f xf tf2 is? fn-next])
is more difficult to interpret and understand mentally without diving deeper or spending a bit of time muscling various functions into it and seeing what happens.
@ian: designing library code is an interesting challenge. On the one hand I tend to prefer longer variable names instead of short ones with comments that explain what they mean. On the other hand, I'm tending to use a fair number of single-letter argument/variable names these days when I'm working on functions that are very flexible and abstract because as the author I know what they mean, but I also find that reducing them to a single letter lets me see the shape of the code better. So for functions where the shape is meaningful I use the single-letter names, and only spell out the longer name when that is important or when that particular argument or variable is what needs to stand out in that function.
Single-letter names are pretty common in clojure code and now I have a better understanding of why that is.
Its a balancing act. When I write code and decide the names of things or even how the code is formatted and whether things are split into multiple lines or not I'm always asking myself what would make the code most understandable to a user of the code?
@harshdeep: I found Clojure for the Brave and True to be excellent. Plus Clojure Koans and 4clojure problems for practice.
Sometimes its the variable names and argument names that are most important. Other times its the shape of the function and what gets passed in is so generic that long names for those things get in the way of seeing the shape.
Also is the user going to be a casual once in a while user, or are they going to be a power user who will become familiar with the conventions within the code base?
I think that the context of the code makes a difference. Private internal functions, sure use ks, m, xs, etc. If they're public facing and you want to tell a story about what your function does, then maybe use longer names.
I try to wear all those hats as I work on a library. So the more internal and private functions are for power use and are abstract and shape-oriented. The public api is easier, more verbose, expects less of the user, and uses the language from the domain of the user, rather than clojure-speak.
I agree with most of what you said, but I think that the "...as the author I know what they mean..." statement is concerning. I think even just some type hints or a few words in the docstring would be enough for it to be accessible without a lot of effort.
But I also brought it up because I don't know the answer or what's good or bad in this situation. I just wanted to bring it up to see what others thought about it.
I'd love to be wrong in the sense that I fear Clojure code can become alien to read when coming back to it when it looks like this.
Prismatic schema does a good job of making sure that your function's signatures are understandable. It adds overhead to the dev process and of course is hard to retrofit into legacy projects, though.
@ian: I don't disagree with that, and I'm not trying to say that I'm following my own advice to the letter, but here is an example. In my ergo
code, which is founded on a recursive process, I have the notion of generation
as an incrementing integer that gets passed to a lot of functions. In some cases I spell it out fully, in others I don't. I actually went and spelled it out in a bunch of functions at one point and then returned them all back to just g
because I saw that this long variable name actual made the shape of the function harder to discern and in that context the shape, and a few differences in that shape, was what was meaningful, even to a beginner. So the cognitive burden of expecting the reader of the code to have figured out by that point that the letter g
is used for generation
was worthwhile. At the same time, there is no case of the letter g
ever being used to represent anything else. And while this all might be well-known for some programmers, I guess for me it just drove home the value of single-letter variables which I now understand and appreciate when I see them used well in other people's code. To me it says, these arguments are expected, and you need to know what each letter stands for, but after you've done that realize that they aren't as important as the other stuff taking place within this function.
I brought of Schema when I initially brought this up but I haven't seen many large or complex systems use it and have a good story to tell. The most recent news in any sort of typed Clojure that I've seen is CircleCI saying they're abandoning core.typed and moving to Schema.
I try to follow the Clojure Style Guide conventions and what I see in Clojure source or the code I see others write that I respect.
I don't think clojure code ends up looking alien. In fact, just the opposite. The more you are exposed to clojure code that uses the same, short naming conventions, the quicker you can read code.
Being somewhat new could be the reason you're not seeing Schema in large systems. Larger systems are usually an older codebase and are less likely to have something new that's going to change the way that functions are written.
Same thing with component. Component is awesome, but it pretty much requires rewriting your entire app if you try to use it with an existing codebase.
And when you write code from a bottom-up functional style you have a lot of little functions that work on datatypes in a generic way so why not name them generically. Then the later functions that build on these little building-block pieces will have more domain-specific aspects and that's where I switch to domain terminology and longer names.
I have to say, I think I spend almost as much time thinking about what to name things as I do how to make a function work. Goes back to my early years doing database design and having to name lots of fields. Then object design. Now library design in Clojure. At least Rich has an appreciation for language. I like that.
Fair enough regarding Schema (and Component). I just have some experimenting to do I suppose. I think the only way I'll be satisfied with an answer is by working on a large code base myself and realizing it's not an issue. :)
I’m trying to use clojure.walk, but I’m not seeing all of the elements that I was expecting to see. e.g. when I walk [:a [:b [:c]]]. inner sees :a and [:b [:c]]; if I want to walk that tree, do I call walk recursively? that doesn’t seem like a thing
Is there something like map
that only evaluates for side effects? Like doall, but without the for-syntax so I can use it with ->>
?
What do I need to add to my deftype to make it work with the following:
(defn neighbor-freq-8
"Returns a map of cell, neighbor-count pairs."
[cell-maker-f cells]
(frequencies (mapcat (partial neighborhood-8 cell-maker-f) cells)))
@cfleming: I don't understand, what's wrong with (doall (map ...))
?
if cell-maker-f
is vector
it works, if it is my ->Cell
it isn't working - I think I need to define an equality method perhaps.
@val_waeselynck: Probably nothing . I was just curious if something existed already that didn’t create a result seq.
@cfleming: sounds like either doseq
or dorun
I have (hashCode [_] (hash [x y]))
but not sure how to code the (equals
or if I need something else
@val_waeselynck: doseq
has for-syntax and dorun
just walks the seq. Although I’m not clear on the distinction between doall
and dorun
, looking at the doc again.
I always seem to have to twist things around when I've used one of the dorun/doall/doseq functions
why does deftype
feel like a black art? I'm having to dig all over to figure out how to work with the darn things. 😞
@cfleming: just new to them and learning the ropes and trying to make my Cell type do what I want
I mean, seriously, this looks a bit harsh compared to the rest of my file:
#?(:cljs
(deftype Cell [^long x ^long y]
Positioned
(position [_] [x y])
(x [_] x)
(y [_] y)
IHash
(-hash [_] (hash [x y]))
IIndexed
(-nth [_ i]
(case i
0 x
1 y))
(-nth [_ i not-found]
(case i
0 x
1 y
not-found)))
:clj
(deftype Cell [^long x ^long y]
Positioned
(position [_] [x y])
(x [_] x)
(y [_] y)
Object
(equals [_ that] (and (= x (.-x ^Cell that)) (= y (.-y ^Cell that))))
(hashCode [_] (hash [x y]))
clojure.lang.Indexed
(nth [_ i]
(case i
0 x
1 y
(throw (IllegalArgumentException.))))
(nth [this i _] (nth this i))))
(defmethod clojure.core/print-method Cell [this ^java.io.Writer writer]
(.write writer (str "<Cell " (position this) ">")))
Yeah, could be familiarity, it’s mostly the reader conditionals that jump out at me, but I’m not used to them.
And the differences in the clj and cljs versions of the various protocols that one gets exposed to
Hey, look at what I just came across in my code: (cr/quick-bench (doall (map neighborhood-8-a sample-points)) :verbose)
@meow: you could do:
n.b. the reader conditionals probably aren’t quite right, but you get the idea
@danielcompton: good point, yes
You could even combine IIndexed with clojure.lang.indexed as they have a similar impl