Fork me on GitHub
#beginners
<
2019-06-13
>
introom02:06:20

how do you put an element at the tail of a list?

alexmiller02:06:35

well first, you should avoid needing to do that

introom02:06:50

sure. was curious. only know concat to do that.

alexmiller02:06:03

yeah that would be what I would suggest

introom02:06:37

(macroexpand-1 (lazy-seq โ€™(3)))

introom02:06:42

the console directly outputs 3

introom03:06:23

i want to see the (new clojure.lang.LazySeq stuff)

seancorfield03:06:21

@i Do you mean like this?

user=> (type (lazy-seq '(3)))
clojure.lang.LazySeq
user=>

seancorfield03:06:45

The REPL by default tries to realize and print sequences.

introom03:06:54

@seancorfield i want to see what the macro lazy-seq expands into.

introom03:06:12

so LazySeq is the thing that is expanded and then get executed.

seancorfield03:06:07

Ah, you want the source function then...

seancorfield03:06:26

user=> (source lazy-seq)
(defmacro lazy-seq
  "Takes a body of expressions that returns an ISeq or nil, and yields
  a Seqable object that will invoke the body only the first time seq
  is called, and will cache the result and return it on all subsequent
  seq calls. See also - realized?"
  {:added "1.0"}
  [& body]
  (list 'new 'clojure.lang.LazySeq (list* '^{:once true} fn* [] body)))
nil
user=> 

seancorfield03:06:00

Or am I still not understanding you?

seancorfield03:06:58

Or perhaps this?

user=> (macroexpand '(lazy-seq '(3)))
(new clojure.lang.LazySeq (fn* [] (quote (3))))
user=> 
macroexpand and macroexpand-1 need to be passed code so the form needs to be quoted.

seancorfield03:06:36

(they are functions so, in calls to them, Clojure will evaluate the arguments first)

seancorfield03:06:40

You had (macroexpand-1 (lazy-seq '(3))) with no quote on the form so Clojure evaluated (lazy-seq '(3)) first, then called macroexpand-1 on the result.

phrsantos03:06:24

Hey there. I have a vec of vec that are integers and I need a to create a display function that will map numbers to char or strings. Something to get [[0 1] [0 2] to [["zero" "one"] ["zero" "two"]]. I'm not sure how to start it though.

seancorfield04:06:37

@hp_pedrors Is it for arbitrary numbers, or just for a small, known set of numbers?

phrsantos04:06:29

It's a small set of numbers. Right now, about 6.

seancorfield04:06:31

How about a map then? {0 "zero", 1 "one", 2 "two",,,}

phrsantos04:06:35

Is it easy later on to retrieve the key from the value in a map?

phrsantos04:06:58

So if I want the other way around, getting 0 from "zero".

seancorfield04:06:58

It's easy to invert a map, yes.

seancorfield04:06:17

(zipmap (vals the-map) (keys the-map)) will produce an inverted map.

seancorfield04:06:53

There's also (clojure.set/map-invert the-map)

๐Ÿ‘ 1
phrsantos04:06:33

Oh that's brilliant!

phrsantos04:06:48

Thank you very much.

seancorfield04:06:22

And if you want something for arbitrary numbers...

seancorfield04:06:27

...drum roll...

seancorfield04:06:41

(! 508)-> clj -Sdeps '{:deps {com.ibm.icu/icu4j {:mvn/version "64.2"}}}'
Clojure 1.10.1
user=> (import 'com.ibm.icu.text.RuleBasedNumberFormat 'com.ibm.icu.util.ULocale)
com.ibm.icu.util.ULocale
user=> (.format (RuleBasedNumberFormat. (ULocale. "En") RuleBasedNumberFormat/SPELLOUT) 1234.56)
"one thousand two hundred thirty-four point five six"
user=> (.format (RuleBasedNumberFormat. (ULocale. "Fr") RuleBasedNumberFormat/SPELLOUT) 1234.56)
"mille deux cent trente-quatre virgule cinq six"
user=> 

phrsantos04:06:18

:shocked_face_with_exploding_head:

phrsantos04:06:53

Not right now, thanks haha.

seancorfield04:06:01

You made me curious so I did a few searches ๐Ÿ™‚

phrsantos04:06:26

Looked scary at first.

phrsantos04:06:36

Now after reading it 3-4 times it makes sense.

seancorfield04:06:12

It took me a few minutes on Bing to locate a StackOverflow answer that included a library rather than reams of nasty Java code to do it half-baked.

seancorfield04:06:11

Then I looked on Maven Central for the library coordinates and searched on Bing for the actual package names for the classes used in the SO post (why do people never include the dang import statements in their Java code!!! ๐Ÿ˜  )

seancorfield04:06:40

Then it was pretty easy to fire up a clj REPL with that dependency, pull in the classes and try their example...

phrsantos04:06:23

The REPL helps a lot!

seancorfield04:06:35

Always, always, always run a REPL and experiment!

๐Ÿ‘ 1
๐Ÿ’ฏ 1
seancorfield04:06:31

I have my main work REPL open 24x7 for days at a time (sometimes weeks!), and then I'll run "scratch" REPLs as needed to experiment with new stuff I see talked about here, or to help people out.

seancorfield04:06:57

My main work REPL is actually REBL, with a Socket REPL running (I use Atom/Chlorine for my editor). I love REBL!

phrsantos04:06:54

Should private functions all be at the top and public all at the bottom of a ns, or should private functions associated with their public should be close together? Or does a guideline for that not exist?

didibus04:06:38

Functions have to be in the order that they are used

didibus04:06:29

So if A uses B, B has to come before

didibus04:06:16

That's the only rule. There's no other convention

phrsantos04:06:19

Oh yea yea. I just mean if A uses B, and C uses D, should it be BDAC, or BADC.

seancorfield04:06:09

Well, you can use declare so you can put functions in any order...

didibus04:06:31

Up to you. But there are some common styles, but everyone has their own preferences.

seancorfield04:06:36

...but my advice is to not worry too much about private functions -- they can still be called by other code!

didibus04:06:37

One style is to group public and private together based on what they do. So "BADC". That's what I do.

seancorfield04:06:55

I tend to organize functions in a namespace to be in general groups from lowest-level to highest-level, with comments to introduce each group of related functions.

๐Ÿ‘ 1
seancorfield04:06:15

I sometimes have private functions, but not very often.

didibus04:06:18

Ya, I do exactly the same

didibus04:06:34

I do use private heavily though. But still do the same

seancorfield04:06:45

As an example, our work code base has 3117 fns, 641 of which are private.

didibus04:06:52

If some things are cross cutting utils, I group them at the very top.

didibus04:06:56

Other people though, just put all their private into a separate namespace, make them public and call the namespace like "namespace-impl".

seancorfield04:06:14

In public OSS code, I'm more likely to either use private for stuff that isn't meant to be part of the documented API, or put all that in a .impl namespace (as public functions).

didibus04:06:51

And the third style I've seen, but I'd say it's the least common one is your BDAC one.

didibus04:06:25

Because eventually, it forces you to use declare, and the use of declare isn't very popular. Some people frown upon it.

didibus04:06:12

My beef with not using private is it messes up my autocomplete ๐Ÿ˜‹ in that then it lists way too many fns I don't care about

seancorfield04:06:35

I have often found that I've eventually needed to make a private function public so I can reuse it outside the namespace -- so that's why I've mostly stopped using private functions.

seancorfield04:06:03

Although there is a benefit to using private functions if you run Joker in lint mode -- it will flag any private functions that are not actually used!

didibus05:06:49

Hum, generally, at that moment, I'd just make it public. Or if it's because it's actually a generic util or useful common util, I move it to a common utils namespace

didibus05:06:10

Also, some linters don't support declare, so I'd also probably say don't use it if you don't need it

phrsantos05:06:42

Thanks a lot guys! You have been huge help.

phrsantos05:06:53

I'll finalize some tests tomorrow and turn the project in.

phrsantos05:06:01

Along with some documentation.

jaihindhreddy06:06:19

When I eval (def a (atom 1)), the symbol a points to a var which contains an atom, which contains the Long 1 right?

โœ”๏ธ 1
jaihindhreddy06:06:31

Or does the symbol a point directly to the atom

jaihindhreddy06:06:51

Because I remember Rich saying, you have reference types, which only ever point to values, and you have values.

jaihindhreddy06:06:02

And var pointing to an atom would break that.

andy.fingerhut06:06:43

Vars can "point to" atoms via evaluating an expression like (def a (atom 1)).

andy.fingerhut06:06:28

It is possible after evaluating that to make a point to something else, e.g. an immutable value like 1, or a different atom, or anything else, but most often in Clojure Vars "point at" the same thing for their entire lifetimes.

andy.fingerhut06:06:57

meaning, that is how people use Vars most commonly.

andy.fingerhut06:06:29

You could in Clojure create an atom that contains an atom that contains yet another atom, but there isn't much reason to do so.

๐Ÿ‘ 1
andy.fingerhut06:06:05

I am not sure which thing that Rich said that you are referring to, but whatever he said, it sounds like he is describing what he recommends doing. He is not describing what Clojure strictly limits you to doing.

๐Ÿ’ฏ 1
didibus10:06:28

Did you mean, can the symbol point directly to the atom? Bypassing the Var?

alexmiller10:06:55

Direct linking is about invocation, not values

didibus10:06:23

If so, I don't think so. And I've never seen or heard that you could. But now I too am curious

alexmiller10:06:52

No, thatโ€™s not a thing. The only thing similar is ^:const, but thatโ€™s for inlining compile time constants, which an atom is not

mloughlin11:06:24

How practical is it to write libraries aiming at .cljc? Is it a good habit?

holyjak12:06:07

It depends on the library, I guess. Is it worth the extra work? Though, as a user, I do appreciate when a clojure library also works with clojuescript...

๐Ÿ‘ 2
Alex Sumner12:06:47

@seancorfield sorry, went to bed before you posted your last example on the .. and -> macros! Yes, it does work. Thanks again.

1
Suni Masuno15:06:26

How do people normally test macros?

Suni Masuno15:06:02

(deftest a-test
  (testing "--> macro thread first plus __ placeholder option"
    (is (=  
          (macroexpand '(--> 5 (+ 2) (- 4 __))) 
          '(let* [__ 5 __ (+ __ 2) __ (+ 2 __)] __)))))     
is this a sane pattern?

souenzzo17:06:01

my macros usually looks like this (defmacro my-foo [& args] (my-foo-fn* args &env)) And I test the function

Suni Masuno17:06:08

Well that's neato, thanks

ghadi15:06:07

I test the code that macros generate, not the macro itself

๐Ÿ‘ 2
Suni Masuno15:06:57

something more like

(testing "--> macro thread first plus __ placeholder option"
    (is (= (--> 5 (+ 2) (- 4 __)) -3)))

eskemojoe00715:06:41

Anyone know the difference between immutant.web.middleware/wrap-session and the default ring.middleware.session/wrap-session. The default luminus template clearly prefers the immutant one by putting the wrap-base function like this

(defn wrap-base [handler]
  (-> ((:middleware defaults) handler)
      wrap-auth
      wrap-flash
      (wrap-session {:cookie-attrs {:http-only true}})
      (wrap-defaults
        (-> site-defaults
            (assoc-in [:security :anti-forgery] false)
            (dissoc :session)))
      wrap-internal-error))

kaneko18:06:24

I want to learn Clojure by writing some games. Are there any libraries that you guys would recommend? Or is game programming in Clojure actually quite difficult?

andy.fingerhut18:06:39

I haven't written a game in Clojure and do not have any libraries to recommend, but I do know that multiple people over the last several years have published the source code of games they have worked on in Clojure, and/or written blog articles with some of the steps they followed.

andy.fingerhut18:06:17

This discussion from a couple of years ago has several library recommendations, for a "simple platformer" game the questioner is interested in writing. I suspect the library recommendations might be quite different depending upon the level of graphics and/or animation intensity you want to use.

Mattias19:06:38

Thereโ€™s always Unity ๐Ÿ˜›

kaneko19:06:23

Yeah, thanks guys ๐Ÿ™‚ If I can learn unity I might be able to use arcadia ๐Ÿ˜›

Nate Sutton20:06:03

I was going to ask a question and found it with the tiniest bit of googling but thought I'd share

Nate Sutton20:06:48

if foo_bar_baz is snake case and FooBarBaz is camel case, what is foo-bar-baz?

Nate Sutton20:06:51

kebab case

๐Ÿข 2
noisesmith20:06:01

there's a lib, camel-snake-kebab, usually used for making prettier renames of keys in json or xml data into keywords in maps

noisesmith20:06:26

though often it reduces complexity to just use the original string

Suni Masuno20:06:30

What's the difference between ^:internal and ^:private?

noisesmith20:06:55

private actually does something concrete to the bytecode var created

noisesmith20:06:08

internal is a random keyword as far as the compiler itself is concerned

johnj22:06:58

is there a common technique to automatically add the repl and pprint namespaces to the namespace one is currently working on? without doing a require manually of those namespaces every time one restarts the repl

seancorfield22:06:02

@lockdown- If your workflow is to work in an editor and eval code to the REPL (as it should be, rather than manually typing into the REPL), then your editor's integration should have the functionality you'd need from those namespaces "built in" as various key strokes...

johnj22:06:35

@seancorfield how does those editors do it?

seancorfield22:06:57

Depends on the editor. What are you using?

johnj22:06:08

do they just call require for you automatically?

johnj22:06:02

I'm using emacs with inf-clojure,

seancorfield22:06:29

Ah, then your options may be pretty limited. CIDER/nREPL provides a much richer Emacs experience.

johnj22:06:38

but it doesn't have that feature, but curious what technique is done here

dpsutton22:06:11

inf-clojure-show-var-documentation inf-clojure-show-var-source

dpsutton22:06:14

seems to have both

seancorfield22:06:32

I use Atom/Chlorine and with my cursor on any symbol I can show docs, show source, jump to the definition, all with hot keys for Chlorine's built-in commands. I've added commands to inspect the symbol in REBL, inspect the namespace in REBL, etc. All my evals (form, top-level form, selection) also send the output to REBL so I can browse easily either via the tabular navigation or view data as pretty-printed EDN.

seancorfield22:06:01

@dpsutton Good to know. I wasn't sure how primitive inf mode is. I haven't used it for many, many years.

dpsutton22:06:10

yeah i've only dabbled in it

dpsutton22:06:21

i like the idea of it though. just formatting commands that any repl must understand

seancorfield22:06:22

@lockdown- I know it's a commercial offering but I highly recommend Eric Normand's course on https://purelyfunctional.tv/courses/repl-driven-development-in-clojure/ as an excellent way to develop a really productive REPL-based workflow

johnj22:06:42

@dpsutton I'll see how it does it, what about making the repl pprint?

dpsutton22:06:09

doesn't seem to be anything in there

johnj22:06:55

@seancorfield chlorine and cider are too much magic for me now, was curious to see it all work, does that course uses just a plain repl?

seancorfield22:06:55

It shows workflows based on Emacs/CIDER/nREPL and Cursive, but it's fairly generic and doesn't rely on many of their features.

seancorfield22:06:40

It doesn't still showing "typing directly into the REPL" but only for exploratory stuff but it really does try to focus on eval-from-editor as the primary approach.

seancorfield22:06:23

I'm all in favor of a simple toolchain -- it's why I use Chlorine and stick to a Socket REPL, rather than do anything with CIDER/nREPL -- but I like being able to do most stuff via hot keys from the editor, rather than typing shortcuts in the REPL.

johnj22:06:00

That course seems really helpful

johnj22:06:34

yeah, I'm interested in automating all this stuff from my editor without going all the way to cider, had to much trouble with it

seancorfield22:06:59

It's like nine hours I think. I really enjoyed it (and I recommend it to everyone because I'm a huge advocate of RDD).

seancorfield22:06:11

Also, have you watched Stu Halloway's talks on this topic?

seancorfield22:06:55

One is called Running With Scissors. An older one is called REPL-Driven Development, that he gave to the Chicago Clojure meetup last summer (I think).

johnj22:06:48

Great, found the scissors one

johnj22:06:53

and the one is vimeo

1
seancorfield22:06:47

I'm also no fan of CIDER based on past experience. Same goes for my colleague hiredman (Kevin Downey). It's an amazing piece of tooling but I just had too many odd things happen with it (some were to do with breakage over upgrades, some of it was just Emacs config/tooling).

Ahmed Hassan04:06:55

@lockdown- CIDER looks magic at first but once you are used to it, it works great.

Ahmed Hassan04:06:21

There are only few commands which I use in CIDER.

dpsutton22:06:36

one thing you can do is import all of this stuff to user.clj and work from there. rather than being "in" whatever ns, just require it into the user ns and then you know you have source, doc, apropos, and pretty print as you like

noisesmith22:06:46

@lockdown- I use a shorthand macro in my user.clj that does all the "prep" I want for an active namespace

seancorfield22:06:08

Also, eval (clojure.pprint/pp) that will pretty-print the last thing printed (and works from any namespace).

noisesmith22:06:08

and of course it's automatically valid in ns user in that case

dpsutton22:06:17

you could just run lein repl or clj if you want to be barebones with not magic

johnj22:06:16

Was talking more about automation of all these setup

johnj22:06:56

@noisesmith understood my poor articulation of the problem

johnj22:06:29

@noisesmith do you have it in a gist somewhere?

noisesmith22:06:42

it's pretty idiosyncratic, let me check

noisesmith22:06:14

and it doesn't even currently have the clojure.repl / clojure.pprint stuff :/ - easy to whip up oneself

johnj22:06:14

interesting flow ๐Ÿ˜‰ thanks going to try to digest it

Nate Sutton22:06:18

@seancorfield you've watched that whole thing?

seancorfield22:06:06

@nate_clojurians Yes I have! I started while it was still being developed so I've seen some of the lessons multiple times as they've changed while Eric was developing the course.

Nate Sutton22:06:31

cool! it's a big commitment to get thaaaat much video

Nate Sutton22:06:49

8 hours jeeze

seancorfield22:06:51

I tend to watch Eric's stuff on 2x speed... that "Southern drawl", and all that ๐Ÿ™‚

Nate Sutton22:06:16

not a bad idea

seancorfield22:06:09

If you can arrange your screen to have the video in one half and your editor in the other, you can "play along" in your editor/REPL at the same time -- recommended!

Nate Sutton22:06:24

yeah, I might get a membership

Nate Sutton22:06:27

the site needs some css help

seancorfield22:06:08

He's an engineer, not a designer ๐Ÿ™‚ But I know he'll appreciate feedback on how to improve the UI.

Nate Sutton23:06:10

I just sent along a bunch of stuff

Nate Sutton23:06:42

I hope it's helpful

Nate Sutton23:06:58

there's just a bunch of minor things that would make it look so much better

Nate Sutton23:06:13

@seancorfield good call on the 2x speed