Fork me on GitHub
#clojure
<
2015-09-24
>
harshdeep00:09:31

Hello guys, I am new at learning Clojure. Could someone explain me the term "not-nil?" and difference between "not-nil?" and "not"?

amacdougall00:09:03

Does not-nil? even exist?

akiva00:09:14

It doesn’t.

amacdougall00:09:43

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.

harshdeep00:09:49

Is not used in setting up pre conditions?

amacdougall00:09:57

So (complement even?) would give you a function identical to odd?

amacdougall00:09:09

By the same token, (complement nil?) gives you a not-nil?.

amacdougall00:09:38

(nil? nil) => true; ((complement nil?) nil) => false.

amacdougall00:09:46

I don't know if this is actually helpful.

harshdeep00:09:01

It is helpful.

harshdeep00:09:19

Could you suggest me some links by which I can study Clojure?

akiva00:09:41

Is it wrong that I’m now chuckling over the idea of a complement of complement?

amacdougall00:09:51

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?

amacdougall01:09:05

(compliment <@U08B448C9>) ; why thank you

amacdougall01:09:16

Or more likely, @amacdougall is not an atom

akiva01:09:35

@amacdougall: I’d go with user on success and false on failure.

amacdougall01:09:37

@harshdeep, I got a lot out of The Joy of Clojure.

akiva01:09:49

That way you can comp it with other functions.

amacdougall01:09:29

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!

harshdeep01:09:09

Now, if I write in the command

harshdeep01:09:40

but if I write, (complement nil? nil), it gives me an ArityException.

amacdougall01:09:45

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.

harshdeep01:09:22

So you mean to say that "complement" exists out of the clojure.core, right?

amacdougall01:09:24

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.

beppu01:09:33

@harshdeep: ((complement nil?) nil)

amacdougall01:09:54

Try this instead:

(defn not-nil? (complement nil?))

(not-nil? nil)
(not-nil? "hello!")

akiva01:09:27

I wouldn’t go through these hoops though. (not (nil? nil)) should suffice.

amacdougall01:09:31

Wait, not defn; use def. simple_smile

harshdeep01:09:31

Both of them work, I just misplaced brackets.

harshdeep01:09:37

Thanks guys.

akiva01:09:40

You are literally saving one character.

amacdougall01:09:55

The complement thing is for illustration; don't do it in real life!

amacdougall01:09:07

complement can be useful, just not for nil?.

akiva01:09:09

I’ve seen good uses of it but it’s one of those outliers.

harshdeep01:09:25

Just one more question, does Clojure have applications in the field of Artificial Intelligence?

akiva01:09:26

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.

amacdougall01:09:29

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.

amacdougall01:09:53

I have a feeling that your choice of language is not a strong factor in your success with AI-related projects these days.

sanitar4eg01:09:09

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

amacdougall01:09:16

If you're interested in an object database with powerful history features, I think Datomic might be right up your alley, @sanitar4eg .

amacdougall01:09:28

Never used it, but I understand that's what it's good for.

sanitar4eg01:09:08

Unfortunately at this stage is not possible to change the database, it is common mysql

amacdougall01:09:48

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.

amacdougall01:09:09

Bear in mind that you could always use the Java code directly! Clojure is good at interoperating with Java.

amacdougall01:09:19

You could build a Clojure app around the Java ORM.

amacdougall01:09:21

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.

amacdougall01:09:46

Its lessons apply to every language I've ever used.

sanitar4eg01:09:46

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

amacdougall01:09:11

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.

amacdougall01:09:40

And I just got all my tests to pass. As usual, I was forgetting the argument order of < and >....

amacdougall01:09:24

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.

danielcompton01:09:15

some? does what you would expect not-nil? to do

danielcompton01:09:51

@amacdougall: I think of the > as a crocodile. It always bites the bigger number

amacdougall01:09:44

Yeah, but in Clojure, that means it skips everything in its way and goes to the far right! 🐊

akiva01:09:54

Why in the heck didn’t I think about some?. Off my game over here.

amacdougall01:09:10

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.

amacdougall01:09:38

some? is clearly the name of a function which tests a predicate against a collection, you know?

akiva01:09:46

But yeah, good point there as well. It’s not entirely clear just by reading it.

amacdougall01:09:19

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.

amacdougall01:09:31

For example, virtually every damn thing about Javascript.

danielcompton01:09:36

(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)

amacdougall01:09:15

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.

danielcompton01:09:27

@amacdougall: you’re not the only one who finds that name confusing

akiva01:09:37

If I was concerned about creating a clear DSL, I’d wrap some?.

amacdougall01:09:10

Anyway, it's not really a big deal. But yeah.

amacdougall01:09:18

Anyway, time to get at least a little relaxation out of the evening. Wrote some more tests, life is fine.

firthh01:09:10

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 sense

meow03:09:23

I'm late to the party but off-the-cuff I would think that (complement complement) would be the same as identity

akiva03:09:19

Yeah, it would be essentially. I was just being silly.

meow03:09:22

just having fun

meow03:09:31

@harshdeep: What kind of AI are you interested in doing with Clojure?

meow03:09:35

I'm doing a lot with L-systems and Cellular Automata here: https://github.com/decomplect/ion/blob/master/src/ion/ergo/core.cljc

meow03:09:26

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.

meow03:09:48

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)))))

meow03:09:44

That is one fractal-generating beast there... simple_smile

danielcompton06:09:16

@firthh putting side effects in an or like that is pretty dirty 😈

firthh06:09:05

@danielcompton: yeah I know it's not pure, but in that case the (do-something) is also making a call out to the database.

firthh06:09:19

so it's never going to be pure

ian07:09:50

@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

ian07:09:08

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.

socksy08:09:56

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?

chrisbetz09:09:58

@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/

socksy10:09:14

hey @chrisbetz simple_smile 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

samebchase10:09:24

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?

samebchase10:09:18

Has anyone run into this behaviour before?

colin.yates10:09:02

@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?

samebchase10:09:19

@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.

colin.yates10:09:29

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...

samebchase10:09:42

I have used set-fn-validation! before, but that is for functions defined using Schema's own defn and not the vanilla Clojure defn.

colin.yates10:09:05

yeah, thought so. I am grabbing at straws - I don’t know then.

colin.yates10:09:14

what does restarting the repl do?

colin.yates10:09:49

@samebchase: a clean REPL and it does fail to validate for me

samebchase10:09:54

I just created a new project and tried and it works, but does not work in my existing project.

colin.yates10:09:52

I guess the next step is to start ripping stuff out to get the smallest reproducible project then?

samebchase10:09:27

Hm. I've run into this before, will try some other stuff and see.

chrisbetz11:09:29

@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.

socksy12:09:13

@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)

meow12:09:47

@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.

luis12:09:42

hello hello! first time here, good to see you all!

danoyoung12:09:38

@chrisbetz: do you plan on adding support for SparkSQL/Dataframes to sparkling?

meow12:09:21

@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.

joachim12:09:51

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?

meow12:09:02

I've done both in the process of getting to where I'm trying to go. simple_smile

joachim12:09:18

I guess not … I'll just put a #’ in front of the function call then..

potetm12:09:37

@ian How do you ever know the signature of a library function without reading documentation/source?

meow12:09:55

@akiva: what's the complement of reduce?

potetm12:09:31

@meow I think you just blew a circuit in my brain.

meow12:09:07

@potetm: I've been working on too much generative stuff. simple_smile

meow13:09:01

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)))

meow13:09:11

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.

chrisbetz13:09:28

@socksy: Hi, make sure to try the improvements on testing broadcast-dependant code using @-sign-deref, if necessary. That's nice ;)

borkdude14:09:33

there seems to be some quarrel about clojure and core.typed on social media today

borkdude14:09:49

we already knew that clojure is not haskell right

agile_geek14:09:26

@borkdude: I haven’t used core.typed but I always had some concerns about typing as an afterthought to the language.

agile_geek14:09:05

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.

chris14:09:48

lol ambrose keeps retweeting these things

chris14:09:55

I wonder how he feels about this

agile_geek14:09:05

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?

borkdude14:09:15

my experience with core.typed is that every time I try it, something was broken simple_smile I haven't used it seriously in any project, but I think it's a matter of maturity

borkdude14:09:03

and of course, if type checking is an afterthought, it will never be as good

borkdude14:09:44

@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

borkdude14:09:39

I know someone who prefers writing in Haskell, just because of the development experience, not because of some sense of safety

agile_geek14:09:45

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.

agile_geek14:09:59

@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!

chris14:09:14

haskell can’t check my clients to see what they actually want

jeffh-fp14:09:41

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

borkdude14:09:29

@jeffh-fp: isn't that something most statically typed languages can do?

jeffh-fp14:09:11

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-fp14:09:50

Maybe it’s something more typical in statically typed functional languages? (preferring function composition, relying on pure functions more)

agile_geek14:09:37

@jeffh-fp: I suspect you're right

borkdude14:09:07

hmm, function composition, yeah ok. Maybe in Scala you'd have the same experience?

borkdude14:09:17

or what about java 8?

jeffh-fp14:09:23

I try to avoid Java simple_smile

jeffh-fp14:09:43

are you trolling me? 😉

borkdude15:09:18

@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. simple_smile

gary15:09:09

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.

borkdude15:09:08

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.

amacdougall15:09:43

@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.

csmith15:09:22

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

csmith15:09:28

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

ghadi15:09:29

Bodil isn't even here and she stirred up shit...

ghadi15:09:51

Oh Twitter!

chris15:09:04

haha that’s why I follow her, I think she loves stirring the pot

csmith15:09:21

haha yeah. I think Bodil is hilarious. I don’t take some of those things too seriously

chrisbetz15:09:25

@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.

christianromney17:09:39

pass args to the JVM to control memory allocation

honza17:09:15

@christianromney: and set it to what? 128mb?

christianromney17:09:06

depends on your actual usage. you should use a profiler like https://www.yourkit.com/ to understand your app’s actual needs.

christianromney17:09:47

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

honza17:09:16

k, thanks

meow18:09:24

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))))

meow18:09:49

The "problem" is the vswap! incrementing.

meow18:09:12

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 %))

meow18:09:52

nevermind, I just realized they wrapped it in a lambda to add the hint

meow18:09:42

that fixed it: (vswap! generation #(inc ^long %))

harshdeep19:09:22

I wanted to ask, as I dont have prior Lisp experience, can I still learn Clojure?

robert-stuttaford19:09:57

of course you can

robert-stuttaford19:09:06

how do you think the first lisper did it -wink-

robert-stuttaford19:09:17

so many great resources available to the beginner now

harshdeep19:09:49

I am doing from internet resources & "The Joy of Clojure" book. Is it enough?

robert-stuttaford19:09:47

JoC is great, but not for new-to-Clojure folks

harshdeep19:09:12

Which book do you suggest then?

robert-stuttaford19:09:23

Living Clojure by @gigasquid, Clojure for the Brave and True are two great starting points

robert-stuttaford19:09:38

http://www.purelyfunctional.tv/ has nice ‘casts you can buy if you’re into that

harshdeep19:09:30

So Living Clojure, I feel is good. I am gonna download it, and go through it. Thanks simple_smile

ian19:09:32

@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.

ian19:09:24

@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.

meow19:09:52

@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.

meow20:09:22

Single-letter names are pretty common in clojure code and now I have a better understanding of why that is.

meow20:09:01

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?

jstew20:09:23

@harshdeep: I found Clojure for the Brave and True to be excellent. Plus Clojure Koans and 4clojure problems for practice.

meow20:09:09

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.

meow20:09:17

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?

jstew20:09:08

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.

meow20:09:23

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.

ian20:09:30

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.

meow20:09:50

@jstew: definitely

ian20:09:10

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.

ian20:09:12

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.

jstew20:09:22

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.

meow20:09:52

@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.

ian20:09:45

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.

meow20:09:50

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.

meow20:09:23

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.

jstew20:09:43

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.

jstew20:09:22

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.

meow20:09:24

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.

meow20:09:29

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.

ian20:09:19

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. :)

lvh21:09:50

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

cfleming22:09:44

Is there something like map that only evaluates for side effects? Like doall, but without the for-syntax so I can use it with ->>?

meow22:09:27

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)))

val_waeselynck22:09:19

@cfleming: I don't understand, what's wrong with (doall (map ...)) ?

meow22:09:28

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.

cfleming22:09:02

@val_waeselynck: Probably nothing simple_smile. I was just curious if something existed already that didn’t create a result seq.

val_waeselynck22:09:27

@cfleming: sounds like either doseq or dorun

meow22:09:20

I have (hashCode [_] (hash [x y])) but not sure how to code the (equals or if I need something else

meow22:09:52

Cell is basically (deftype Cell [^long x ^long y]

meow22:09:31

so I need it to behave like [x y] for most purposes

cfleming22:09:06

@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.

cfleming22:09:37

Actually, doall retains the head, looks like - looks like dorun is what I want.

meow22:09:41

@cfleming: one of them retains the head, the other doesn't and returns nil

meow22:09:16

I always seem to have to twist things around when I've used one of the dorun/doall/doseq functions

meow22:09:22

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. 😞

cfleming22:09:59

@meow: What’s the issue you’re having with deftype?

meow22:09:01

got it: (equals [_ that] (and (= x (.-x ^Cell that)) (= y (.-y ^Cell that))))

cfleming22:09:31

Ah, sorry, hadn’t read your earlier messages

meow22:09:42

@cfleming: just new to them and learning the ropes and trying to make my Cell type do what I want

cfleming22:09:53

BTW you’re using Cursive, right? It can generate those methods for you.

cfleming22:09:19

Put the caret inside the deftype form, and hit Cmd-N if you’re on OSX

meow22:09:53

oh, really?

meow22:09:01

I'm on Winblows

cfleming22:09:18

Um, then it’s something else - one sec

meow22:09:27

plus I'm doing this in a .cljc and need it for both langs

cfleming22:09:43

Code->Generate...

cfleming22:09:58

Hmm, that might be a little flakey, try it and see

cfleming22:09:13

You want to use Override methods to override an Object method.

meow22:09:37

nice, but I still need to know what I'm doing...

meow22:09:01

and deftype code is just, so, ugly

meow22:09:45

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) ">")))

meow22:09:50

just saying

meow22:09:54

maybe I'm just getting used to it

cfleming22:09:52

Yeah, could be familiarity, it’s mostly the reader conditionals that jump out at me, but I’m not used to them.

meow22:09:11

And the differences in the clj and cljs versions of the various protocols that one gets exposed to

meow22:09:31

Hey, look at what I just came across in my code: (cr/quick-bench (doall (map neighborhood-8-a sample-points)) :verbose)

cfleming22:09:27

Hehe, nice. In that case, I think you actually want dorun.

danielcompton22:09:48

n.b. the reader conditionals probably aren’t quite right, but you get the idea

danielcompton23:09:42

You could even combine IIndexed with clojure.lang.indexed as they have a similar impl

meow23:09:16

even better, I'm not seeing any performance improvement using Cell instead of a simple [x y] vector 😞

meow23:09:29

oh well, baby steps

meow23:09:54

time for a break and food...