beginners

Getting started with Clojure/ClojureScript? Welcome! Also try: https://ask.clojure.org. Check out resources at https://gist.github.com/yogthos/be323be0361c589570a6da4ccc85f58f.
sova-soars-the-sora 2021-03-07T00:32:35.445400Z

okay neat

sova-soars-the-sora 2021-03-07T00:33:40.445800Z

Hmmm. Seems like chrome doesn't care xD

sova-soars-the-sora 2021-03-07T00:35:23.446Z

Hmmm.

sova-soars-the-sora 2021-03-07T00:35:49.446400Z

So I tried "nativefier" on a login endpoint https://github.com/nativefier/nativefier

sova-soars-the-sora 2021-03-07T00:36:10.446900Z

the CSRF token is changing, but it's apparently not getting the right one via this embedded electron app

sova-soars-the-sora 2021-03-07T00:36:50.447200Z

not mission-critical, but still a perplexing issue.

sova-soars-the-sora 2021-03-07T00:40:46.447400Z

Huh. I dunno.

sova-soars-the-sora 2021-03-07T00:41:05.447900Z

I thought maybe I was passing in an outdated token or something... the web version works fine, the nativefier version does not

Jim Strieter 2021-03-07T01:35:27.448400Z

When I type: ((apply comp '((+ 1) (+ 1))) 1) I get: Execution error (ClassCastException) at clj-event-loop.core/eval2305 (form-init8093888511408098339.clj:1). clojure.lang.PersistentList cannot be cast to clojure.lang.IFn

Jim Strieter 2021-03-07T02:04:22.449100Z

sure

seancorfield 2021-03-07T02:52:12.449300Z

You have a quoted list in there so it's just data, not functions.

seancorfield 2021-03-07T02:52:47.449500Z

((apply comp [inc inc]) 1) will work.

seancorfield 2021-03-07T02:55:25.449800Z

Also (+ 1) is not a function, it's a value: (+) is 0, (+ 1) is 1, (+ 1 2) is 3.

seancorfield 2021-03-07T02:55:51.450Z

inc is "add 1" or your could use (partial + 1) and get a function that adds one.

Kifah 2021-03-07T11:52:58.452400Z

Hi, can anyone help me with setting up Intellij?

Kifah 2021-03-07T11:54:05.453200Z

I've set up a barebones cljs project as per https://andrearichiardi.com/blog/posts/clojurescript-cursive-shadow-setup.html, but IDEA won't stop complaining, and fetching maven repositories fails, like so-

Kifah 2021-03-07T11:55:38.453600Z

Kifah 2021-03-07T11:56:21.454Z

This is what my deps.edn looks like

simongray 2021-03-07T12:12:10.454800Z

@kifah FYI there's a #cursive channel too

Kifah 2021-03-07T12:14:59.454900Z

Thank you Simon, crossposted there 🙏:skin-tone-3:

Jim Newton 2021-03-07T14:09:22.460600Z

Every time I restart doing something in clojure, it get confused again. Can someone help me understand why this doesn't equal 0 when I is an integer?

(reduce + 0 (concat (range (- i) -1)
                                     (range 1 i))))

Jim Newton 2021-03-07T14:14:39.461Z

I see, it is because range DOES NOT include its upper bound ....

Jim Newton 2021-03-07T14:16:51.461800Z

if I add the numbers (range -99 -1) to the numbers in (range 1 99), I don't get 0.

Jim Newton 2021-03-07T14:20:08.462600Z

I have a question about loop/`recur`. If I have a function which DOES work recursively, is it still better to write it as loop if possible? i.e., is there some speed advantage?

Jim Strieter 2021-03-07T14:45:48.465500Z

Singletons are 1 instance per JVM instance, right? (As opposed to 1/cpu, 1/motherboard, etc.) I wouldn't think multiple JVM's on the same machine would share runtime, but I wanted to check.

Jim Strieter 2021-03-07T14:47:11.466100Z

Is there a way that I can write a clojure fn to operate on a Java instance without having to pass the Java instance into every method call?

Jim Newton 2021-03-07T14:57:33.470300Z

I was trying to rewrite a small but precise Scala function in Clojure, and I am unable to make it as concise. in Clojure it is roughly twice the size. The function is purely functional, doesn't depend on OO paradigms, so my instinct is it ought to be very concise in Clojure. Here is the Scala code.

def treeFold[A](seq: Seq[A])(z: A)(f: (A, A) => A): A = {
  def dwindleTree(stack: List[(Int, A)]): List[(Int, A)] = {
    stack match {
     case (i, b1) :: (j, b2) :: tail if i == j =>
dwindleTree((i + 1, f(b2, b1)) :: tail) case _ => stack
}}
val stack = seq.foldLeft((1, z) :: Nil) {
    (stack, ob) => dwindleTree((1, ob) :: stack)
  }
stack.map(_._2).reduce { (a1, a2) => f(a2, a1) } }
One thing that makes this concise is that the first case in the pattern match case (i,b1)::(j,b2)::tail if i== j simultaneously checks two different conditions. In the Clojure code I need two concentric if forms.
(defn tree-fold
  "omitting doc string...."
  [f z coll]
  (letfn [(dwindle-tree [stack]
            (loop [stack stack]
              (if (empty? (rest (rest stack)))
                stack
                (let [[[i b1] [j b2] & tail] stack]
                  (if (= i j)
                    (recur (cons [(inc i) (f b2 b1)] tail))
                    stack)))))]
    (let [stack (reduce (fn [stack ob]
                          (dwindle-tree (cons [1 ob] stack)))
                        (list [1 z])
                        coll)]
      ;; stack is guaranteed to have at least one element
      (reduce (fn [a1 a2] (f a2 a1))
              (map second stack)))))
Isn't there a better way?

alexmiller 2021-03-07T15:00:53.470600Z

depends what you mean by "singleton" and "runtime", but generally yes

alexmiller 2021-03-07T15:01:21.470800Z

there are several ways to work with "ambient" objects: • Clojure dynamic vars (available and overridable on a per thread basis) • Java threadlocals (threads only see "their" version) • global state (all Clojure vars are global state)

✅ 1
borkdude 2021-03-07T15:04:15.471400Z

@jimka.issy Perhaps this can be made concise with core.match. I will give it a try

alexmiller 2021-03-07T15:04:52.471500Z

that said, all of these mechanisms result in functions that depend on external "stuff" not visible to the caller. in general those kinds of functions are harder to test, harder to understand, and harder to maintain, and should be considered an exceptional case to use only when you've thought about all the tradeoffs

✅ 1
2021-03-07T15:09:24.471700Z

loop/recur will not grow and shrink the stack, whereas a recursive function will. The default stack depth is small enough that you will often cause an exception to be thrown due to stack exhaustion in a few thousand depth recursive calls. You can configure it higher, but loop/recur will avoid that completely

borkdude 2021-03-07T15:15:33.472200Z

I came up with this, but it's pretty ugly, so not really an improvement:

(require '[clojure.core.match :refer [match]])

(defn tree-fold
  "omitting doc string...."
  [f z coll]
  (letfn [(dwindle-tree [stack]
            (loop [stack stack]
              (match (nnext stack)
                     ([[i b1] [_ b2] & tail] :guard (fn [[[i _] [j _]]] (= i j)))
                     (recur (cons [(inc i) (f b2 b1)] tail))
                     :else stack)))]
    (let [stack (reduce (fn [stack ob]
                          (dwindle-tree (cons [1 ob] stack)))
                        (list [1 z])
                        coll)]
      ;; stack is guaranteed to have at least one element
      (reduce (fn [a1 a2] (f a2 a1))
              (map second stack)))))

(tree-fold + 0 [1 2 3])

borkdude 2021-03-07T15:15:53.472700Z

I couldn't find out how you can re-use the bindings in the :guard

Jim Strieter 2021-03-07T15:22:15.473400Z

@alexmiller thank you! Yeah, after I wrote that I realized that that's kind of like global variables. Good to know it's possible but not preferable

Jim Strieter 2021-03-07T15:22:20.473600Z

🙂

Jim Newton 2021-03-07T15:29:15.474200Z

reusing the bindings with :guard is the important part of guard. right?

Jim Newton 2021-03-07T15:31:04.474600Z

Thanks. BTW what is nnext ?

borkdude 2021-03-07T15:31:17.474800Z

True. I guess you could do it like this. But this isn't buying you much over let. Maybe just accept that Clojure is longer than Scala here ;)

(dwindle-tree
 [stack]
 (loop [stack stack]
   (match (nnext stack)
          ([[i b1] [j b2] & tail])
          (if (= i j)
            (recur (cons [(inc i) (f b2 b1)] tail))
            stack)
          :else stack)))

borkdude 2021-03-07T15:31:47.475Z

same as (next (next ..))

Jim Newton 2021-03-07T15:32:53.475400Z

is it necessary, the Scala code matches stack rather than matching (next (next ...))

borkdude 2021-03-07T15:34:10.475600Z

(empty? (rest (rest stack))) will return the same truthyness as (nnext stack)

Jim Newton 2021-03-07T15:35:39.476200Z

Or I could take it as a challenge to implement a pattern matching which sane guards ? Grins. Don't complain unless you're willing to submit a fix.

borkdude 2021-03-07T15:36:25.477Z

Yes. core.match is extensible btw, but I'm not sure if it is possible to "forward" bindings into a predicate... I think it should be, but not sure.

1
Jim Newton 2021-03-07T15:37:15.477300Z

of course I can reduce one line by using tail recursion rather than loop/reduce

Jim Newton 2021-03-07T15:37:41.477900Z

I know (for my algorithm) that the maximum recursion is log(length(coll))

Jim Newton 2021-03-07T15:48:25.478800Z

I can put the operands of reduce on a single line if I make reduce-1 a local function. that trades two lines for two lines.

(defn tree-fold
  "Like the 3-arg version of reduce except that does not compute from left-to-right
  but rather effectingly by grouping in concentric groups of two. e.g.
   (+ (+ (+ 1 2) (+ 3 4)) (+ (+ 5 6) (+ 7 8))) ...
  The remaining (right-most) elements are partitioned into 2's as much as possible.
  Intermediate values become unreferenced as quickly as possible, allowing them to 
  be GCed"
  [f z coll]
  (letfn [(dwindle-tree [stack]
            (if (empty? (rest (rest stack)))
              stack
              (let [[[i b1] [j b2] & tail] stack]
                (if (= i j)
                  (dwindle-tree (cons [(inc i) (f b2 b1)] tail))
                  stack))))
          (reduce-1 [stack ob]
            (dwindle-tree (cons [1 ob] stack)))]
    (let [stack (reduce reduce-1 (list [1 z]) coll)]
      ;; stack is guaranteed to have at least one element
      ;; and have length <= log_2(coll)+1
      (reduce (fn [a1 a2] (f a2 a1))
              (map second stack)))))

2021-03-07T16:09:17.480500Z

I haven't looked at the specifics of this code, but people have often made their custom variants of cond macros that do combinations of conditional tests and bindings that are specific to each branch. Not sure if that helps with code size / expressivity here, but it is a reasonably common desire that isn't part of Clojure core library (except if-let and when-let , and also somewhat cond-> and cond->>)

1
Jim Newton 2021-03-07T16:19:52.481400Z

yes. in my case small-code-size relates to putting a code snippet on a beamer (powerpoint) slide to display to non-closure experts.

Jim Newton 2021-03-07T16:20:27.481600Z

I'm giving a talk in a few weeks to a group of what I believe to be data scientists, about use cases for non-standard fold/reduce patterns.

Jim Newton 2021-03-07T16:21:01.481800Z

i.e., why a person might be dissatisfied with the default fold implementation in your language of choice, and what you can do about it.

Jim Newton 2021-03-07T16:21:44.482Z

the original paper is written for a scala crowd, but I'd like to give the same talk to a non-scale crowd.

Jim Newton 2021-03-07T16:21:59.482200Z

super-optimized-scala can look like line-noise.

Jim Newton 2021-03-07T16:22:35.482400Z

as per my original post https://clojurians.slack.com/archives/C053AK3F9/p1615129053470300

Jim Strieter 2021-03-07T17:08:13.483100Z

I'm trying to import a local Clj namespace from the same project, different file.

Jim Strieter 2021-03-07T17:09:59.484600Z

I type: (:use 'my-package-name.my-namespace) and get nil. Then I try to call something from that namespace: (some-func 0.) and get: Unable to resolve symbol in this context What am I doing wrong?

borkdude 2021-03-07T17:10:44.485200Z

@jimka.issy Can you give more context? Where are you typing this expression? In a REPL outside of an ns form?

borkdude 2021-03-07T17:11:02.485600Z

Then you should use (use ....), not the keyword

borkdude 2021-03-07T17:11:31.486Z

(:use 'my-package-name.my-namespace) returns nil because it tries to look up the keyword in the symbol

Jim Strieter 2021-03-07T17:15:39.486400Z

In a repl outside of a ns form - yes

borkdude 2021-03-07T17:15:56.486700Z

(use 'my-package-name.my-namespace)

Jim Strieter 2021-03-07T17:16:18.487200Z

@borkdude when you say it returns nil because it tries to look up the keyword, does that mean it succeeded or failed

borkdude 2021-03-07T17:17:35.488Z

it doesn't do anything namespace related. the expression evaluates like (get 'my-namespace :foo)

borkdude 2021-03-07T17:18:21.488500Z

e.g. (:foo {:foo 1}) returns 1, because the keyword looks itself up in its argument

borkdude 2021-03-07T17:18:55.489300Z

but (:foo "dude") returns nil because there is no :foo key in a string

borkdude 2021-03-07T17:19:05.489600Z

you are just hitting a confusing case of this while trying to use use

Jim Strieter 2021-03-07T17:41:11.490800Z

My problem is that when I type my-package-name, the repl fills in .core. I can type in .my-namespace manually, but then the repl doesn't let me call anything from the namespace I just imported. Even after I type my-namespace manually, the repl won't let me call anything from that namespace

2021-03-07T18:35:22.494100Z

You have to load code in order to use it, if you haven't loaded the file that defines a namespace, then the namespace doesn't exist and you can't use it

Jim Strieter 2021-03-07T18:35:55.495400Z

@hiredman Oh. Okay!

2021-03-07T18:36:05.495800Z

It isn't like java where you can use a long fully qualified named anywhere regardless of if you import a class or not

2021-03-07T18:36:46.497Z

require and use both also load the code

Jim Strieter 2021-03-07T18:37:38.497900Z

@hiredman is there a way to load a file that implies local project? for instance, tells repl to look in src/my-project/.../someFile.clj without typing src/my-project

2021-03-07T18:38:54.499300Z

Namespace names implicitly map to resource names relative to classpath roots

2021-03-07T18:39:27.000200Z

So when you require the namespace foo.bar, clojure looks for a foo/bar.clj resource

2021-03-07T18:40:25.001100Z

Where is you aren't familiar with java resources, you can for now just think of resources as a file

2021-03-07T18:42:05.003200Z

So generally you will use some tool to launch your repl, which puts your src directory on the classpath, so when you require foo.bar, src/foo/bar.clj will be loaded

2021-03-07T22:00:46.007600Z

On the topic of namespaces. I just worked through a problem and I’d like to confirm my understanding. 1. I’m connecting to a remote REPL 2. my main (ns …) declaration requires another namespace in a deeper directory 3. that file doesn’t exist on the remote REPL because I’m developing and organizing on my local machine 4. I get a FileNotFoundException because my other namespace files aren’t on the remote host (they’re local) 5. as long as I go to the buffers of the namespaces I need and load the files, everything works My understanding is that if the namespace is already loaded into the remote REPL, it won’t look for the file on the remote host. Am I understanding this correctly?

2021-03-07T22:13:39.007700Z

sorry if I’m relying on information in my own head for this to make sense. Here’s an example: I have the following files on my local host where I’m editing the code: • myapp/src/core.cljmyapp/src/otherstuff/thing.clj Those files aren’t on the remote host where the REPL is running. In myapp/src/core.clj, I have the following line: (ns core (:require [otherstuff.thing] :as thing]) When I eval that last line I get the exception as I would expect since the file isn’t there on the remote host. If open the local file myapp/src/otherstuff/thing.clj and load the buffer into the remote REPL, the problem goes away.

2021-03-07T22:21:48.007900Z

Whenever you do a require or use on a namespace in Clojure, it remembers this in a *loaded-libs* internal variable (which you can examine if you are curious to see what it contains). Future require/`use` (or their equivalents inside of an ns form) will avoid reloading a namespace that *loaded-libs* says has been loaded already.

2021-03-07T22:22:22.008100Z

Even if you are not trying to do any dynamic development at the REPL, this is a critical time-saver, because you don't want a namespace required from 20 other namespaces to be loaded 20 times.

2021-03-07T22:28:29.008300Z

ok, just confirming that I got it. If it’s loaded, it goes in *loaded-libs* and won’t be looked for to load anymore when you require it in a (ns …) command. So it doesn’t have to exist remotely if you loaded it locally.