Fork me on GitHub
#beginners
<
2021-03-16
>
cschep04:03:16

I have a vector of maps, each map has a key :id, i’d like for this vector to actually be a map from the :id to a map of the rest of the data in the map

cschep04:03:26

is there a cool flatten trick here

cschep04:03:29

extract, pick something

cschep04:03:46

or do i create an empty map and loop through and assoc in? doesn’t feel very functional

cschep04:03:48

maybe reduce.

dpsutton04:03:30

(into {} (map (juxt :id identity)) your-coll)

dpsutton04:03:24

most codebases end up with some utility function that's u/key-by that does this to some effect. up to you how you resolve if there's the same id in more than one of the maps. first wins, last wins, etc

🎯 3
cschep04:03:56

this is really awesome, juxt combines the functions :id, which is a keyword but why do you need identity?

cschep04:03:44

oh that’s the piece that puts the rest of the map in as the value

dpsutton04:03:48

((juxt :id identity) {:id 1 :other :stuff}) #_ -> [1 {:id 1, :other :stuff}]

dpsutton04:03:06

yeah. you make tuples of [k v] and then pour those (into {})

cschep04:03:34

that’s awesome, thanks!

seancorfield04:03:10

This is one of those things where you often hear people say "what use is a function that always just returns its argument?" and here's a great example.

cschep04:03:54

yeah, I would have asked that question too! but that’s really useful 🙂

0xclj08:03:02

When should one use Exception. vs ex-info ?

delaguardo09:03:31

when consumer of your function expects to see specific Throwable class such as Exception

👍 1
alexmiller12:03:10

generally, when writing Clojure, I almost always use ex-info

☝️ 1
✔️ 2
zackteo12:03:37

Not sure what I'm doing wrong exactly but I can't seem to get this clojars library working with a minimal example https://github.com/kahuin/kahdemlia I added [kahdemlia "0.1.0-SNAPSHOT"] to my project.clj and tried to run

(ns ds-test.core
  (:require [kahdemlia.core :refer [make-node!]]))

zackteo12:03:30

but i will get

2. Unhandled clojure.lang.Compiler$CompilerException
   Error compiling kahdemlia/core.cljc at (1:1)
   #:clojure.error{:phase :compile-syntax-check,
                   :line 1,
                   :column 1,
                   :source "kahdemlia/core.cljc"}
             Compiler.java: 7648  clojure.lang.Compiler/load
                   RT.java:  381  clojure.lang.RT/loadResourceScript
                   RT.java:  372  clojure.lang.RT/loadResourceScript
                   RT.java:  459  clojure.lang.RT/load
                   RT.java:  424  clojure.lang.RT/load
                  core.clj: 6126  clojure.core/load/fn
                  core.clj: 6125  clojure.core/load
                  core.clj: 6109  clojure.core/load
               RestFn.java:  408  clojure.lang.RestFn/invoke
                  core.clj: 5908  clojure.core/load-one
                  core.clj: 5903  clojure.core/load-one
                  core.clj: 5948  clojure.core/load-lib/fn
                  core.clj: 5947  clojure.core/load-lib
                  core.clj: 5928  clojure.core/load-lib
               RestFn.java:  142  clojure.lang.RestFn/applyTo
                  core.clj:  667  clojure.core/apply
                  core.clj: 5985  clojure.core/load-libs
                  core.clj: 5969  clojure.core/load-libs
               RestFn.java:  137  clojure.lang.RestFn/applyTo
                  core.clj:  667  clojure.core/apply
                  core.clj: 6007  clojure.core/require
                  core.clj: 6007  clojure.core/require
               RestFn.java:  408  clojure.lang.RestFn/invoke
                      REPL:    1  ds-test.core/eval19109/loading--auto--
                      REPL:    1  ds-test.core/eval19109
                      REPL:    1  ds-test.core/eval19109
             Compiler.java: 7177  clojure.lang.Compiler/eval
             Compiler.java: 7166  clojure.lang.Compiler/eval
             Compiler.java: 7132  clojure.lang.Compiler/eval
                  core.clj: 3214  clojure.core/eval
                  core.clj: 3210  clojure.core/eval
    interruptible_eval.clj:   87  nrepl.middleware.interruptible-eval/evaluate/fn/fn
                  AFn.java:  152  clojure.lang.AFn/applyToHelper
                  AFn.java:  144  clojure.lang.AFn/applyTo
                  core.clj:  665  clojure.core/apply
                  core.clj: 1973  clojure.core/with-bindings*
                  core.clj: 1973  clojure.core/with-bindings*
               RestFn.java:  425  clojure.lang.RestFn/invoke
    interruptible_eval.clj:   87  nrepl.middleware.interruptible-eval/evaluate/fn
                  main.clj:  437  clojure.main/repl/read-eval-print/fn
                  main.clj:  437  clojure.main/repl/read-eval-print
                  main.clj:  458  clojure.main/repl/fn
                  main.clj:  458  clojure.main/repl
                  main.clj:  368  clojure.main/repl
               RestFn.java:  137  clojure.lang.RestFn/applyTo
                  core.clj:  665  clojure.core/apply
                  core.clj:  660  clojure.core/apply
                regrow.clj:   20  refactor-nrepl.ns.slam.hound.regrow/wrap-clojure-repl/fn
               RestFn.java: 1523  clojure.lang.RestFn/invoke
    interruptible_eval.clj:   84  nrepl.middleware.interruptible-eval/evaluate
    interruptible_eval.clj:   56  nrepl.middleware.interruptible-eval/evaluate
    interruptible_eval.clj:  152  nrepl.middleware.interruptible-eval/interruptible-eval/fn/fn
                  AFn.java:   22  clojure.lang.AFn/run
               session.clj:  202  nrepl.middleware.session/session-exec/main-loop/fn
               session.clj:  201  nrepl.middleware.session/session-exec/main-loop
                  AFn.java:   22  clojure.lang.AFn/run
               Thread.java:  834  java.lang.Thread/run

1. Caused by java.io.FileNotFoundException
   Could not locate clojure/spec__init.class, clojure/spec.clj or
   clojure/spec.cljc on classpath.

jkxyz12:03:32

It’s failing to compile the kahdemlia.core namespace because it requires clojure.spec , which is a namespace that doesn’t exist in later versions of Clojure. You can try explicitly adding [org.clojure/clojure "1.9.0-alpha15"] to your dependencies, and it should compile. But I wouldn’t suggest using this library for anything serious unless you fork it and update it to work with a newer Clojure version

zackteo12:03:56

I see I see hmmmm, I'll just clone the repo and explore the library directly instead 🙂

jkxyz12:03:02

That also works for trying it out. The spec library is now under clojure.spec.alpha, it seems like clojure.spec only existed for that alpha release of Clojure. So should be possible to update the library to work with the latest Clojure

athomasoriginal21:03:17

I have a dev/user namespace. Things are working well. I have added a few dev tools like user/dbg. What are some of the approaches for configuring the REPL so I can reference user/dbg as just dbg in other namespaces without having to run require or use in each namespace where I would like to access them?

andy.fingerhut22:03:53

I don't know of any way to automatically do that off the top of my head, but if you have an editor or IDE where you have a key sequence of your choice assigned to "evaluate the expression just before the cursor", so you don't have to type the same expression more than once, it can be good to have frequently used expressions like `(require 'user.dbg)` or `(use 'user.dbg)` in a file at the top level of your project, e.g. named something like `scratch.clj`, that you often keep open while working in that project.

andy.fingerhut22:03:51

Having your chosen editor/IDE set up so that a very convenient short key sequence can send expressions to your REPL for evaluation is HIGHLY RECOMMENDED

athomasoriginal00:03:32

That’s a good point. Let me look into the tooling more. With atom/chlorine I normally use execute from whichever namespace i’m currently in. Thus, if i’m in ns.some.place when I execute commands they are from that namespace.

noisesmith01:03:30

I have a function that combines (apply require clojure.main/repl-requires) with loading my utilities from user.clj into the current ns, that gives me the standard things like doc, pprint, source in any ns

👍 1
cschep22:03:18

i’m using an atom to a map, atom of a map? how do you even say that. 🙂 I’m using an atom referencing a map as a database for a tiny app i’m working on. It holds data about baseball players. I have been writing some functions to do data access / updates.

cschep22:03:29

(defn update-player
  [id key value]
  (swap! league
         (fn [current-state]
           (assoc-in current-state [id key] value))))

cschep22:03:40

this seems to work great, but it prints the entire database in the repl everytime

cschep22:03:08

maybe a success or fail would be good or silent success error on fail.. does swap! ever fail? or.. how would silence its output?

andy.fingerhut22:03:36

Regarding terminology, I think "an atom containing a map" is fairly common.

cschep22:03:42

containing! nice.

andy.fingerhut22:03:52

"referencing" is clear, too

andy.fingerhut22:03:29

In a REPL, any time any function can return a value that is very large in being printed, you can do something like (def x1 (some-expression-returning-big value)) , and it will only show #'user/x1 instead of the big value. The big value will be stored in x1 for future reference/manipulation.

andy.fingerhut22:03:16

Unless the function you pass to swap! can throw an exception, I don't know of any reasons why swap! can fail

andy.fingerhut22:03:32

Even then, swap! should leave the current value contained in the atom there.

cschep22:03:48

right that makes sense

cschep22:03:08

it seems to be updating the atom AND returning the new value

cschep22:03:43

Atomically swaps the value of atom to be:
(apply f current-value-of-atom args). Note that f may be called
multiple times, and thus should be free of side effects.  Returns
the value that was swapped in.

andy.fingerhut22:03:44

That is what the last sentence of the doc string printed by (doc swap!) says it should do.

cschep22:03:52

ha ha nice, thanks for the pointer

andy.fingerhut22:03:26

See also swap-vals! for its different, and sometimes useful, return value

cschep22:03:13

that’s cool, both the old and new

cschep22:03:50

i wrapped the swap! call in a count call to return far less info, is that something people do like, maybe i could wrap it in do and return nil?

andy.fingerhut22:03:46

A Clojure function body is already implicitly wrapped in a do, without having to type (do ...), so you can make the last expression nil in the body if you always want to return nil

andy.fingerhut22:03:50

If you aren't worried about large values accidentally being printed at a REPL, in development it can often be nice when functions return a useful value, even if you do not always use it. But yes, I see people sometimes returning a value like nil when they explicitly want that.

cschep22:03:45

oh that’s really useful thanks, i didn’t know about the implicit do

cschep22:03:53

(defn update-player
  [id key value]
  (swap! league
         (fn [current-state]
           (assoc-in current-state [id key] value)))
  (str "updated " id))

cschep22:03:55

this is kinda useful

cschep22:03:03

but yeah who knows maybe having the whole value there is good

cschep22:03:06

anyway, thanks!

👍 1