Fork me on GitHub
#clojure
<
2018-12-13
>
Sturm02:12:53

I'm looking at packaging Clojure for Guix - can anyone tell me where the source for the bin/clojure shell script lives? I can't see it in the main clojure git repo.

❤️ 4
emccue02:12:44

Now that clojure is on java 1.8 might IFn start to extend from builtin java function interfaces beyond Callable and Runnable?

Sturm02:12:46

Thanks @alexmiller. Do you know if there's a script that merges the built clojure/clojure with clojure/brew-install to make something like what's found at https://download.clojure.org/install/clojure-tools-1.9.0.X.tar.gz?

Alex Miller (Clojure team)05:12:59

That repo is where the build happens

Alex Miller (Clojure team)05:12:58

The build basically runs script/package.sh

eraserhd14:12:32

Is anyone working on a TUI REPL thing like REBL that uses Datifiable/Navigable? Something like datawalk?

lilactown16:12:11

I haven’t see anything like that yet

lilactown16:12:03

I have a question about datafy. I expected to be able to implement the protocol via metadata, but I can’t seem to get it cooperate:

user=> (def x ^{:clojure.datafy/datafy (constantly [3 4 5])} [1 2 3])
#'user/x
user=> (meta x)
#:clojure.datafy{:datafy #object[clojure.core$constantly$fn__5657 0x49c6c24f "clojure.core$constantly$fn__5657@49c6c24f"]}
user=> (d/datafy x)
[1 2 3]
user=> (def x ^{:clojure.datafy/datafy #(str "foo")} [1 2 3])
#'user/x
user=> (d/datafy x)
[1 2 3]

bronsa16:12:30

needs to be a symbol not a keyword

bronsa16:12:51

{`d/datafy (..)}

lilactown16:12:07

same behavior 😕

user=> (def x ^{`d/datafy #(str "foo")} [1 2 3])
#'user/x
user=> (d/datafy x)
[1 2 3]

lilactown16:12:16

this is with latest RC5

ghadi16:12:19

with-meta, not ^{}

bronsa16:12:00

that shouldn't make a difference @ghadi

ghadi16:12:36

Oh whoops - it’s the wrong symbol

ghadi16:12:05

Should be clojure.core.protocols/data fly

bronsa16:12:17

yep that's it

lilactown16:12:35

🙂 that worked!

lilactown16:12:40

mystery solved

ghadi16:12:53

Gah, phones. Data fly is up for the taking as a library name

lilactown16:12:11

user=> (def x (with-meta [1 2 3] {`clojure.core.protocols/datafy (fn [_] 1)}))
#'user/x
user=> (d/datafy x)
1

bronsa16:12:55

FWIW the literal metadata syntax was perfectly fine

bronsa16:12:08

for collection literals it's (mostly) equivalent to using with-meta

lilactown16:12:31

got it. thank you both for the help!

lilactown16:12:30

I got confused because it seems to be implemented differently in CLJS

lilactown16:12:55

in CLJS:

(def y (with-meta [1 2 3] {:clojure.datafy/datafy (fn [_] 1)}))

(d/datafy y)
;; => 1

bronsa16:12:19

datafy is not even a protocol in cljs

bronsa16:12:36

no no it isn't

lilactown16:12:39

it’s in master branch

bronsa16:12:44

that's matching the old initial implementation that clojure had

bronsa16:12:00

@lilactown no, the protocol function in cljs is cljs.core/-datafy

bronsa16:12:05

not clojure.datafy/datafy

bronsa16:12:24

but that keyword thing is how it was implemented in clojure too, before metadata protocol extension got introduced

bronsa16:12:28

I expect that to change in cljs too

lilactown16:12:37

ah I thought you were saying that Datafiable didn’t exist 😛

bronsa16:12:52

the thing is, in that example you're not making use of the protocol at all

bronsa16:12:23

@mfikes I assume you're aware of the new impl in clojure?

bronsa16:12:44

(also, why does cljs not have a clojure.core.protocols namespace? that seems like an odd diversion from clojure)

mfikes16:12:47

Yeah, the datafy port was done a while back, so Clojure could have moved a bit from it since.

Takis_20:12:32

hello, can i use a transient hash-map as an atom,and many threads change it ? with persistent hash-map it works,with transient it doesn't . its my code bug or its transients?

Takis_20:12:35

transients supposed to be used from only 1 thread?

eraserhd20:12:10

atoms need immutable data, since swap! needs to be pure

eraserhd20:12:27

er, I mean swap! needs a pure f.

eraserhd20:12:06

atoms will transparently retry on collisions from thread, and if you store mutable data in them, you will get a bad state

manutter5120:12:29

@takis_ what problem are you trying to solve by putting transient data in an atom?

Takis_20:12:07

i thought that persistent data -structures would be slower for large data

eraserhd20:12:11

takis_: While this is true, going mutable is tricky. I would not recommend doing so until you have evidence you need to.

Takis_20:12:13

its a 2D vector,and many threads add lines to it

hiredman20:12:15

I would strongly recommend building it and measuring, your intuition is almost certainly wrong

manutter5120:12:11

The Clojure core devs have put a lot of effort into making the persistent data as fast as possible.

Takis_20:12:36

do you know if its possible to define in Clojure a synchronized method?like in Java a method that max 1 thread can use

hiredman20:12:54

if you need a mutable multithreaded map juc's concurrenthashmap is right there

manutter5120:12:09

Yeah, there’s locking

eraserhd20:12:18

takis_: Short answer is yes. The long answer is, "wait a minute, ..."

manutter5120:12:35

(doc locking)
-------------------------
clojure.core/locking
([x & body])
Macro
  Executes exprs in an implicit do, while holding the monitor of x.
  Will release the monitor of x in all circumstances.

eraserhd20:12:30

Atoms are designed to use STM and be, usually, faster than locking. locking is mostly for interop with Java, and it is used infrequently.

Takis_20:12:43

i know that you can lock an object,but when i tried it was slow

Takis_20:12:03

ok thank you alot for your time,i am new actually

Takis_20:12:13

but clojure very nice

hiredman20:12:50

locking is always going to slow down multithreaded programs

hiredman20:12:19

(locking in general, including java's synchronized)

eraserhd20:12:49

takis_: it sounds like you want something like Clojure's reducers, maybe? https://clojure.org/reference/reducers

Takis_20:12:12

maybe alot to read and many to try thank you all 🙂

worlds-endless20:12:28

How can I refer to components of my project.clj from within my program? In particular, I need to get the :version from project.clj

enforser20:12:48

The version is available in different places based off how you run the app - i.e. lein repl vs. as an uberjar. I think the solution provided in that doc will work in most cases - but remember to test it out in whatever sort of environment the app is being run in.

worlds-endless20:12:20

Interesting. It looks like there is no real way to just read the edn of project.clj, then?

dpsutton20:12:23

it isn't necessarily edn. there's a reason the extension is clj not edn

enforser20:12:44

You can read in the project file like you would read in any other EDN file, then parse out the version - but the issue is you don't always have the project file available to you, depending on how the app is being run/compiled

worlds-endless20:12:08

Compiling my apps via uberwar, so I don't know that project.clj persists

dpsutton20:12:15

here's an example where you can't really read it

worlds-endless20:12:13

Ok. Hard to test, though, since it's repl-incompatible

enforser21:12:55

We build our war files and deploy them to have an open REPL port which you can connect to and run the function to grab the version

enforser21:12:50

i.e. with immutant you can specify which port to connect to in your project.clj. https://github.com/immutant/lein-immutant/blob/master/docs/deployment.md then you can connect to the REPL with lein repl :connect host:port

worlds-endless21:12:54

wow. That's cool

worlds-endless16:12:14

Is it possible for project.clj to look at a config file for certain values, like version?

timgilbert21:12:56

You can use something like lein-v for that: https://github.com/roomkey/lein-v

timgilbert21:12:39

...it externalizes your version to a git tag and then it has middleware that replaces the value in project.clj

jaide21:12:20

What would be the clojure equivalent to this python snippet?

import os
path = "~/Downloads"

{
    z[0].replace(path, '')[1:]: z[1]
        for z in os.walk(".") if z[0].replace(path, '') and not z[2]
}

jaide21:12:32

I’m working on this too. Seems like we would have to start with file-seq

Noah Bogart22:12:49

What does os.walk do?

Noah Bogart22:12:19

What does the output look like?

jaide22:12:27

It’s building a dictionary of folders mapped to a list of empty children. os.walk returns a tree of files

noisesmith22:12:03

you could construct the equivalent tree by splitting the paths of items from file-seq and using those paths with assoc-in or update-in

noisesmith22:12:05

user=> (pprint (file-seq (java.io.File. ".")))
(#object[java.io.File 0xdbd8e44 "."]
 #object[java.io.File 0x7ac0e420 "./foo"]
 #object[java.io.File 0x78383390 "./foo/bar"]
 #object[java.io.File 0xdb57326 "./foo/bar/baz"]
 #object[java.io.File 0x34a875b3 "./Investor Type no PII.csv"]
 #object[java.io.File 0x4748a0f9 "./Untitled spreadsheet - Sheet1.csv"])

noisesmith22:12:34

if you map str on the files, you just get the path strings

noisesmith22:12:40

@jayzawrotny

user=> (pprint (reduce (fn [t p] (assoc-in t p {})) {} (map #(clojure.string/split (str %) #"/") (file-seq (java.io.File. ".")))))
{"."
 {"foo" {"bar" {"baz" {}}},
  "Investor Type no PII.csv" {},
  "Untitled spreadsheet - Sheet1.csv" {}}}
nil

jaide22:12:26

Pretty close, I can work with that. Here’s the test file structure and the actual output:

## File Tree

# (root)
#  |- a (dir)
#  |  |- b (dir)
#  |  |  |- (empty)
#  |- c (dir)
#  |  |- d (dir)
#  |  |  |- (empty)
#  |- e (dir)
#  |  |- f.txt
#

## Output

# {'/a': ['b'],
#  '/a/b': [],
#  '/c': ['d'],
#  '/c/d': []}

noisesmith22:12:55

oh also my snippet above doesn't differentiate files from directories

jaide22:12:09

(require '[clojure.pprint]
         '[clojure.string :as string])

(defn directory?
  [file]
  (.isDirectory file))

(defn directory-with-no-files?
  [file]
  (and (directory? file)
       (empty? (->> file
                    (.listFiles)
                    (filter #(.isFile %))))))

(defn relative-name
  [path dir]
  (let [dir-path (str dir)]
    (string/replace dir-path (re-pattern path) "")))

(defn pair-files
  [path dir]
  [(relative-name path dir)
   (->> dir
        (.listFiles)
        (filter directory?)
        (map #(.getName %)))])

(defn find-empty-dirs
  [path]
  (->> path
       ()
       (file-seq)
       (drop 1)
       (filter directory-with-no-files?)
       (sort)
       (map #(pair-files path %))
       (into {})
       (clojure.pprint/pprint)))

(find-empty-dirs "/Users/jay/Projects/map-comp/test/")

jaide22:12:13

Is what I got so far

noisesmith22:12:42

so really what you want isn't a tree, but sort of a weird adjacency-list

noisesmith22:12:54

where every item also includes all parents

noisesmith22:12:58

(in its key)

jaide23:12:27

Oh, sorry that wasn’t clear.

jaide23:12:17

Sounds like (file-seq) will do the hard part, the rest seems like string manipulation

noprompt23:12:16

(let [root ( "/Users/jay/Downloads/test/resources/")]
  (transduce
   (comp (remove #{root})
         (keep
          (fn [^java.io.File file]
            (when (.isDirectory file)
              (let [path (.getPath file)
                    ;; Split path into two parts at the last /
                    [parent _] (string/split path #"(?=/[^/]+$)" 2)]
                [parent path])))))
   (fn
     ([m] m)
     ([m [parent child]]
      (-> m
          ;; Update the parent entry to add the child.
          (update parent (fnil conj []) child)
          ;; Create an entry for the child if it doesn't exist.
          (update child (fnil identity [])))))
   {}
   (file-seq root)))

noprompt23:12:00

@jayzawrotny ☝️ here’s an equivalent to your previous post without extra calls to .listFiles and .isDirectory.

jaide23:12:29

I think you just beat me, I was pretty close too

{"/a" ("b"), "/a/b" (), "/c" ("d"), "/c/d" (), "/e" ()}

noprompt23:12:59

I just updated that code to just use keep instead.

noprompt23:12:18

You could use reduce and do all the logic in one reduction function if you want. But, with respect to your desired output, these are the parts.

jaide23:12:50

You could use this script to test against the expected output

mkdir -p a/b
mkdir -p c/d
mkdir e
touch e/f.txt

noprompt23:12:01

That’s exactly what I did.

jaide23:12:15

Ah ok, I misunderstood

noprompt23:12:22

I just replace my path with yours so you could copy and paste it. 🙂

jaide23:12:40

Not to make this uncomfortable but that was extremely thoughtful. Thanks!

noprompt23:12:36

Not uncomfortable at all. Just trying to be maximally helpful. 👍

👍 4
jaide23:12:07

Though there may be a potential issue, I find myself having to replace the (rest) call with (drop 3)

noprompt23:12:40

The rest is to elide the root directory. What does (drop 3 ,,,) buy you?

jaide23:12:34

Right, that’s what I figured it was intended for but I’m finding the root directory is still included

jaide23:12:52

If I add another directory it requires (drop 4) so that the root directory is excluded

jaide23:12:27

But I’m mostly doing this for learning purposes so you don’t need to waste more time on it unless it’s holding your attention 🙂

noprompt23:12:33

Add (comp (remove #{root}) ,,,) like so

(let [root ( "/path/to/whatever")]
  (transduce
   (comp (remove #{root})
         (keep ,,,))
   ,,,
   {}
   (file-seq root)))

noprompt23:12:43

Gotta run! Hope I’ve been helpful!

jaide23:12:50

Immensely, thanks very much

noprompt00:12:37

Oh, I updated the previous code post in the channel with the new requirements. Take care!

metal 4