Fork me on GitHub
#beginners
<
2021-11-30
>
Mattias07:11:06

This is interesting also from a “explaining the Clojure way” to a non-initiate perspective. Good discussion for getting a more holistic view on what all the words mean 🙂

Adam Haber07:11:16

so, just to make sure I understand - if I’m namespace foo which imports some function from namespace bar and I want to edit this function and have the updated function imported to foo, I need make the edit, evaluate the function (which would change to namespace to bar in the repl), go back to foo and re-evaluate the imports and/or the whole namespace (change the repl back to foo)?

practicalli-johnny08:11:21

This is one reason I evaluate code in the source code window, rather than the REPL window, it much more effective. Using the source code window, only the function definition that has changes needs to be evaluate. When evaluating any expression in the source code window, it is within the namespace defined in that file. The whole source code file (buffer/window) can be evaluated also, more useful if there are several changes in the source code

Ngoc Khuat11:11:45

to rephase John’s answer so it more to the point: • if you make the update on file, you just need to evaluate the updated code. • when you use it the foo namespace it should use the updated version without re-evaluate the import Correct me if I’m wrong @U05254DQM

practicalli-johnny12:11:13

Yes, thats correct. You only need to evaluate what has changed regardless of if using a REPL window or source code window. However, code needs to be evaluated in the correct namespace, which the editor does for you in the source code window but the namespace needs to be changed manually in the repl window.

Sam Ritchie14:11:07

(Just noting that this behavior is not required, but just how Calva happens to be implemented today. A good example of how tooling can affect behavior!)

hiredman08:11:15

Depends what you mean by "import", there is something called import in clojure, however it is entirely for interop with java types, and not something you do with clojure namespaces or functions

hiredman08:11:26

The operations on names defined in clojure namespaces are refer or alias

hiredman08:11:31

When use def or defn, you are interning a var, which is a little mutable cell/box/reference with that name in that namespace and setting its value

hiredman08:11:34

The value of a name that resolves to a var is dereferencing the var

hiredman08:11:38

A consequence of that is after (def a 1) (def b a) (def a 2) b will be 1 and a will be 2

hiredman08:11:43

However in (def a 1) (defn f [] a) (def a 2) a will be 2 and calling f will return 2

hiredman08:11:22

And that all is exactly the same in the same namespace or spread across namespaces

cwchriswilliams08:11:54

Are there any standard or commonly used tools for calculating clojure code-metrics? Seems like it would be easy given the code is just data to parse. I'm not sure what would actually be useful right now... Number of top level forms per namespace... form density... most used functions... That type of thing?

Muhammad Hamza Chippa09:11:17

I have a vector of timestamp [1600 1601 1602 1603] and another matrix containing some value [ [1600 1] [1603 3]] . I want final result like [[1600 1] "N/A" "NA " [1603 3]] I was trying to apply filter but it is not working

Martin Půda09:11:33

(defn my-fn [v matrix]
  (let [map1 (into {} matrix)]
    (mapv #(if-let [ret (find map1 %)] ret "N/A") v)))
(my-fn [1600 1601 1602 1603] [[1600 1][1603 3]])
=> [[1600 1] "N/A" "N/A" [1603 3]]

🙌 1
Ed09:11:49

filter will remove something from your input list. To me, it looks like you want to transform the input by looking something up in another data structure. A one-to-one translation would need to use map. Maybe something like this would work?

(let [t      [1600 1601 1602 1603]
        m      [[1600 1] [1603 3]]
        lookup (into {} (map (juxt first identity)) m)]
    (->> t
         (mapv (fn [timestamp] (get lookup timestamp "n/a")))))
Here, I've built a lookup table (a hash-map) of the timestamp -> matrix value, and then applied that lookup to each of the timestamps, putting a default value of "n/a" if it's not found.

2
🙌 1
Muhammad Hamza Chippa10:11:37

Thank you so much brother it worked

👍 1
pavlosmelissinos10:11:10

FYI, even if you don't need the N/As you don't have to use filter:

(let [t [1600 1601 1602 1603]
      m (into {} [[1600 1] [1603 3]])]
  (into [] (select-keys m t)))
;;=> [[1600 1] [1603 3]]

Muhammad Hamza Chippa10:11:17

@U01RL1YV4P7 I am trying to extend your function to the multiple values matrix it is not working (defn mapping-function [v matrix] (mapv #(if-let [ret (find (into {} matrix) %)] ret "N/A") v)) (mapping-function [1600 1601 1602 1603] [[1601 141.33 141.33 141.33 141.33] [1600 141.32 141.24 141.32 141.31]])

Martin Půda11:11:29

My solution works only for vector of pairs- Ed's solution is universal.

🙌 1
emccue15:11:40

While that works…this data structure feels wierd

1
Lycheese10:11:09

While working on getting the TDB storage for Apache Jena working with arachne-framework/aristotle I am using a try-finally block to submit data and close the connection. In Apache Jena transactions this is a 2-step process where you first need to commit and then end the resource usage. Interestingly the code below works only when (.commit dataset) is outside of finally (the equivalent read-only block works just fine with it inside finally). So I have 2 questions: 1. What is the difference in execution between the try and finally parts when no exception occurs? 2. Is it possible to get the return value of (a/add ...) when evaluating the top level sexp instead of (.commit ...)'s? Code:

(let [dataset (TDBFactory/createDataset "tdb/test")]
    (.begin dataset ReadWrite/WRITE)
    (try
      (let [graph (.getGraph (.getDefaultModel dataset))]
        (a/add graph {:rdf/about ::cloud
                      :foaf/firstName "Cloud"
                      :foaf/lastName "Strife"}))
      (.commit dataset)
      (finally (.end dataset))))

Ed12:11:26

I don't know anything about Apache Jena, but the finally block will be executed regardless of an exception being thrown, and cannot change the return value from the try. If you want to return the result of calling a/add you could write something like this:

(let [dataset (TDBFactory/createDataset "tdb/test")]
    (.begin dataset ReadWrite/WRITE)
    (try
      (let [graph (.getGraph (.getDefaultModel dataset))
            graph (a/add graph {:rdf/about ::cloud
                      :foaf/firstName "Cloud"
                      :foaf/lastName "Strife"})]
        (.commit dataset)
        graph)
      (finally (.end dataset))))
since both the try and let blocks will return their last value.

Alex Miller (Clojure team)13:11:04

Notably, the finally behavior differs from Java, where finally can change the return

Martin Půda10:11:02

Following Muhammad's question- if get can have not-found argument, why there is only (find map key)?

Mno11:11:39

because find with a not-found is just get? you can use get with maps as well.

(get {:a 1 :b 2} :c 3)

Mno11:11:46

I didn't read the previous conversation, so I may be lacking context, so I may be misunderstanding the question.

Martin Půda12:11:39

get returns value, find returns map entry, so they are different:

(get {:a 1 :b 2} :a)
=> 1
(find {:a 1 :b 2} :a)
=> [:a 1]
For context, I am talking about this function:
(defn my-fn [v matrix]
  (let [map1 (into {} matrix)]
    (mapv #(if-let [ret (find map1 %)] ret "N/A") v)))
with example:
(my-fn [1600 1601 1602 1603] [[1600 1][1603 3]])
=> [[1600 1] "N/A" "N/A" [1603 3]]
And I want to replace #(if-let [ret (find map1 %)] ret "N/A") with something like #(find map1 % "N/A").

fearnoeval13:11:23

Since find nor RT nor java.util.Map supports something like not-found for returning Map.Entrys, something else would need to be done. IIUC, I'd probably use or, or to relate to your example, #(or (find map1 %) "N/A").

1
Martin Půda13:11:16

Thanks, that's exactly what I was looking for.

👍 1
Muhammad Hamza Chippa14:11:15

I have a complicated map like (defn data {:2017 [["x" 3 2 1] ["y" 3 1 5]] :2018 [["x" 5 3 1] ["y" 4 5 2]]}) I wanted my last result as [["x" (3+5) (2+3) (1+1)]["y" (3+4) (1+5) (2+1)] how can I do that for loop iteration is not working

Arthur15:11:57

Are you sure you want the result to look like this? (3 + 5) won’t work (I guess you can quote it so it “works” tho). Aren’t you looking for (+ 3 5)? Anyways I’d start by turning these vecs into maps, which should make working with this data much easier

Muhammad Hamza Chippa15:11:58

yes yes (+3 5) it is obvious , I wrote it for easy interpretation

Cora (she/her)15:11:03

converting into nested maps would make it a lot easier

🙌 1
Cora (she/her)15:11:20

but assuming that's not an option, there you go

1
Muhammad Hamza Chippa15:11:27

@U02N27RK69K I make the problem simpler I just wanted to achieve something like this now [[5 3 2 ] [1 2 5] [0 1 3]] = [(5+1+0) (3+2+1) (2+5+3)] = [6 6 10]. How can I do that ?

Cora (she/her)15:11:28

you can take my example and play with it to get there

Martin Půda15:11:05

(apply mapv + [[5 3 2 ] [1 2 5] [0 1 3]])
=> [6 6 10]

🙌 1
👍 1
Muhammad Hamza Chippa15:11:38

@U01RL1YV4P7 what about if I wanted to take the average like extending above function [(5+1+0)/3 (3+2+!)/3 (2+5+3)/3] ?

danp16:11:40

Hey all, I’ve got a local jar I am trying to use in my deps.edn. The jar is a Spark JDBC driver downloaded from Databricks. I’m trying to declare as a dependency using `:local/root`, but not quite sure what to put for the maven groupId/artifactId as I can’t find the code on maven. File contents:

{:paths
 ["src" "resources"]

 :deps
 {com.simba/spark {:local/root "resources/SparkJDBC42.jar"}}}
The `com.simba/spark` bit I’ve made up completely. Please could somebody show me where I’m going wrong? 🙂

emccue16:11:16

afaik its made up - so libraries/sparkjdbc

danp16:11:56

great, thanks both

emccue16:11:36

Whatever that password is you typed in and then quickly deleted is a very bad password

Leon16:11:10

i have changed it

Benjamin16:11:53

which is better

(defn foo [a b]
  (+ a b))

(def foo1 (partial foo 1))

(defn bar [a]
  (fn [b]
    (+ a b)))

(def bar1 (bar 1))

Sophie19:11:49

Pretty much the only time where I def a function like this is with a longer comp of really simple functions

(def f (comp g4 g3 g2 g1))

hiredman16:11:26

Neither is great because both capture the value of the bar at definition time (foo and bar) which will cause them to not use new values of foo and bar unless they are also updated

Benjamin16:11:25

so should I just pass the values always

hiredman16:11:25

Something like #(foo 1 %) will get the value of foo Everytime it is called

👍 2
mathpunk17:11:23

I found someone's personal project on Github and I want to try using it. They have no release or clojars reference so I forked it and followed these directions https://clojure.org/guides/deps_and_cli#_using_git_libraries to create this release https://github.com/mathpunk/clojure-sheets/releases/tag/v0.0.1 But, I'm getting Library io.github.mathpunk/clojure-sheets has missing :sha in coordinate when my deps looks like

:deps {org.clojure/clojure    {:mvn/version "1.10.3.929"}
        io.github.mathpunk/clojure-sheets {:git/tag "v0.0.1" :git/sha "464fab2"}

emccue17:11:56

Update your cli tools

1
seancorfield17:11:30

@mathpunk A lot changed in this release in late July: https://clojure.org/releases/tools#v1.10.3.933 (the latest version is 1.10.3.1029)

mathpunk17:11:24

@seancorfield I cannot find the Clojure artifact using coordinates org.clojure/clojure {:mvn/version "1.10.3.933"} -- something different for releases after 'stable'?

ghadi17:11:34

that's the version of the clojure CLI tooling, not clojure itself. For clojure, use 1.10.3

ghadi17:11:53

the clojure CLI tooling can run any version of Clojure

ghadi17:11:07

org.clojure/clojure {:mvn/version "1.10.3"}

ghadi17:11:14

should look like that ^ @mathpunk

mathpunk17:11:57

ah ha! i think we're up, thanks y'all

maverick18:11:18

Which is better for (def data {:key1 value1, :key2 value2} ) (get data :key1) or (:key1 data) ?

pavlosmelissinos18:11:18

From the https://clojure.org/dev/contrib_howto#_coding_guidelines: > Use keyword-first syntax to access properties on objects: (:property object-like-map) > > Use collection-first syntax to extract values from a collection (or use get if the collection might be nil): (collection-like-map key) or (get collection-like-map key). Note that not all collections are keyed by keyword.

seancorfield18:11:07

Calling those the "official coding guidelines" is a bit of a stretch. They are guidelines for contributing code to the Contrib libraries specifically, intended to maintain consistency, but they haven't been updated in a long time. The (community) Clojure Style Guide is probably more broadly applicable: https://guide.clojure.style/#keywords-as-fn-to-get-map-values (and, yes, it recommends keyword-first -- but it doesn't have the nuance about objects vs collections).

👍 1
pavlosmelissinos18:11:47

Well, technically it's an official page that lists some coding guidelines 😛. But sure, the guide is for contrib libraries specifically and it doesn't seem extremely up to date. 😄 However, I'm pretty sure I've seen the distinction between looking up a known vs an unknown (dynamic) key somewhere before. As in (:k1 m) is more idiomatic than (get m :k1) but (get m k) (or (m k)) is more idiomatic than (k m).

seancorfield19:11:47

Yeah, certainly if you don't know what the key is - for example, it could be a string or a non-scalar - then get is the right approach.

👍 1
fappy18:11:46

@anshbenew get allows you to specify a default if key not found

seancorfield18:11:02

(:key1 data ::not-found)
There's a "not found" arity for invocation via a keyword too @anshbenew

fappy18:11:58

user=> (deref (future :val) 60000 (println "should not print, but does. why?"))
should not print, but does. why?
:val

hiredman18:11:25

because deref is a function

hiredman18:11:43

it isn't a short circuiting or

hiredman18:11:18

all the arguments are evaluated first, then the values are passed in to the function, and deref returns the else value if needed

fappy18:11:47

is there a way to do a deref that avoids eval if it doesn’t time out?

hiredman18:11:18

you would build such a thing yourself using some sentinel value and if

maverick18:11:26

So, I think if we are sure that key will exist then get should not be used, right ?

hiredman18:11:52

(if (deref ... ... false) whatever some-other-thing)

fappy18:11:01

ah ok, as long as what might come out normally is truthy or if some-other-thing is ok to do if the future returns a valid falsey thing within the timeout

hiredman18:11:24

or some other sentinel value

hiredman18:11:44

a common one on the jvm is an Object, since those can be compared for identity

hiredman18:11:36

(let [x (Object.) result (deref ... ... x)] (if-not (= x result) ... ...))

dpsutton18:11:40

commonly (Object.) or a namespaced keyword like ::timeout. Technically the object is superior as it cannot be a clash of sentinel vs actual value. In practice the namespaced keyword is similar

fappy18:11:11

much good info thanks!

hiredman18:11:17

get and keyword calling are both fine, generally get is used more for maps that are open, and keyword calling is used more for maps that are closed (struct like)

hiredman18:11:13

but as often as anything you have open maps but use a keyword like a higher order function on them

hiredman18:11:22

(map :whatever something)

Muhammad Hamza Chippa19:11:00

I have the nested vector [[5 3 2] [1 2 5] [0 1 3]] and I wanted something like this [(5+1+0)/3 (3+2+1)/3 (2+5+3)/3 ] how can I achieve that ?

Muhammad Hamza Chippa19:11:17

i know about map it is not working giving wrong result

Darin Douglass19:11:54

what code do you have?

Muhammad Hamza Chippa19:11:52

I am currently (apply mapv + data) it is adding successfully like and giving me desired result of addition I wanted something complex like (5+1+0)/2 and if (3+2+1)/3 means that add then divide with the count of non-zero elements

Muhammad Hamza Chippa19:11:08

but conditionally dividing it giving me tough time

pavlosmelissinos19:11:37

Break down the problem. ignore map for a while Write a function that given n numbers it computes the average of the non-zero elements. Once you have that, use it with map. Solve it for one and then scale up.

🙌 2
Sophie19:11:43

Start with one sublist and write a function for that. Then you can use map with that function. Edit: what the person above me said.

😄 1
🙌 1
Michael W19:11:08

You can perform multiple maps using the threading macro ->>

(->> (apply mapv + data)
     (mapv #(/ %1 3)))

Muhammad Hamza Chippa19:11:54

@UAB2NMK25 yes I know that as well but I have to divide the number of non-zero elements not with 3

Muhammad Hamza Chippa19:11:17

@UEQPKG7HQ I wrote the function for conditional average (defn conditional-average [x] (let [data (filter #(not (= 0 %)) x)] (/ (reduce + data) (count data)))) but it is not working with map as I wanted (map conditional average [[0 3 1] [5 7 2] [3 1 0]]) I want something like this [(0+5+3)/2 (3+7+1)/3 (1+2+0)/2]

pavlosmelissinos19:11:48

Take a look at the examples here and try to understand how map works: https://clojuredocs.org/clojure.core/map

Muhammad Hamza Chippa19:11:50

I transposed the matrix and it worked

R.A. Porter20:11:52

This would also work...

(let [input [[5 3 2] [1 2 5] [0 1 3]]
      f (fn [& n] 
          (let [non-zero (count (remove zero? n))]
            (/ (apply + n) non-zero)))]
    (apply map f input))

🙌 1
seancorfield20:11:14

Beware of input like [0 0 0]

🙌 1
R.A. Porter20:11:51

But NAN goes so well with curry! (Missed that edge case)

1
🅱️ 1
🅾️ 1
0️⃣ 1