Fork me on GitHub
#beginners
<
2019-01-29
>
pberganza04:01:11

This is kind of a noob js/cljs question. I'm adding an event listener to js/document but whenever figwheel hot reloads the page it gets added again. I tried to prevent it by doing this but it keeps on doing the same. (I saw something like this on a Reagent example with js/setInterval so I expected it to work the same).

pberganza04:01:54

The only solution I've found is to prevent figwheel from reloading that file completely.

Vikram07:01:12

Hey, I'm new to clojure and clojure.test . So I've written a simple test case for the project while running C-c C-t p or C-c C-c n it is showing "Not a NREPL dict"

Vikram07:01:14

Can anyone tell me how to rectify that error(Not a nRepl dict)

ordnungswidrig07:01:51

Can you past the versions of cider and nrepl?

ordnungswidrig07:01:49

https://github.com/clojure-emacs/cider/issues/1546 suggests it’t caused by “humane-test-output” but the issue is ancient (2016)

skykanin10:01:15

Is there a way to auto load my clj file on save into the cider repl on emacs? It's pretty annoying having to C-c C-l or C-c C-kevery time I make a change to the file.

borkdude10:01:44

@nicholas.jaunsen personally I’d like to have control over that, but if you’re into this, you can use the reloaded workflow and hook it up to an emacs hook

shidima12:01:53

Can some one point me to what I'm doing wrong here:

(defn create-list [num]
  (let [awnser []]
    (if (empty? num)
      awnser
      (recur (int (/ num 10))
             (conj awnser (mod num 10)))))

shidima12:01:33

I get a argument count error on the recur

joshkh12:01:23

it looks like you're recurring with two arguments, but create-list only access one argument num

restenb12:01:44

you've got two arguments to recur, but only one in your function

bronsa12:01:44

you want (loop [num num answer [] instead of (let [answer [] (p.s. you got a typo)

restenb12:01:02

also you should use loop/recur

restenb12:01:11

basically what they said

shidima12:01:43

@restenb why 2 times num?

joshkh12:01:30

you can also use multiarity to "kick start" the recursion if no answers are yet known:

(defn create-list
  ([n]
    (create-list n []))
  ([n answers]
    (if (< n 10)
      (create-list (inc n) (conj answers n))
      answers)))

joshkh12:01:48

(create-list 0)
=> [0 1 2 3 4 5 6 7 8 9]

joshkh12:01:47

note that recur doesn't play nice with multiarity. it will try to recur on the same function and you'll get the same argument mismatch error

bronsa12:01:48

that's not correct

bronsa12:01:58

you can, and should use recur instead of the second create-list, there

bronsa12:01:22

what you can't do is just recur from the first arity to the second

bronsa12:01:35

maybe that's what you meant?

restenb12:01:33

(loop [num num answer [] just binds your num function parameter to a num local var inside the loop

joshkh12:01:32

restenb's answer is cleaner 🙂 just showing you a more verbose recur

restenb12:01:58

it would help to know what you're trying to do, there's a couple other problems in the function you posted

restenb12:01:37

like it'll probably end up being an infinite recursion if you pass it a number

shidima12:01:36

I'm trying to turn a number into a list of seperate digets. But empty? on a number cant work 🙂

shidima12:01:49

got it working

(defn create-list [num]
  (loop [num num awnser []]
    (if (= num 0)
      awnser
      (recur (int (/ num 10))
             (conj awnser (mod num 10))))))

restenb12:01:57

yes, that might work. the problem I saw was with the (if (empty? num) as I that would seemingly always return false on a number

restenb12:01:37

now your recursion is well-formed with a termination condition on num = 0

restenb12:01:05

also if you're trying to split a number into a list of digits, that can probably be done more readily by just converting the number to string first

restenb12:01:23

(->> num str (map (comp read-string str)))

restenb12:01:01

that will take num as a number and return a list of it's digits, as numbers, by way of string

shidima12:01:24

yes, I was thinking about using a string first, but I wanted to try and use a solution with modulus.

shidima12:01:39

threading macro is also something I need to spend some more time with

restenb12:01:18

I'd still prefer to do this without recursion though

restenb12:01:24

or, without loop/recur I should say

restenb12:01:22

that's a suggested solution using mod and quot

borkdude12:01:37

@shidima a bit hacky maybe: (defn digits [n] (map #(- (int %) 48) (str n)))

joshkh12:01:44

now do a negative number!

restenb12:01:05

you can also just do (map #(Character/digit % 10) (str num))

shidima12:01:16

@restenb but your digits is still using recursion right?

restenb12:01:23

and that'll ... sort of work on negative numbers (first digit becomes -1 if number is negative)

restenb12:01:55

1. @shidima yes, just highlighting that setting up an explicit loop/recur isn't necessary to solve the problem

restenb12:01:37

the above example with quot and mod is the most efficient by far though since you avoid conversions. it can be extended to tackle negative numbers fairly easily

shidima15:01:45

Well, with some help I did the armstrong-numbers problem from http://exercism.io 🙂 Thanks all!

Santiago15:01:14

any pointers on why (mapv #(mapv % (keys (@db :input))) (@db :input)) fails with error: IllegalArgumentException Key must be integer clojure.lang.APersistentVector.invoke (APersistentVector.java:294) :start-time and :end-time contain java.time.Instant and :duration is an integer

seancorfield15:01:56

Is columns meant to be a nested sequence like that?

Santiago16:01:00

I'm not sure, I'm just trying to save a csv with headers, using the keys in the map as the header names. then later I have another function which just appends to this csv without creating the headers

sigmaray21:01:23

Hello I tried to use coast. I had few issues with it.

foobar@foobar-B85-HD3:~/projects/rubbish$ coast new myapp && cd myapp
/home/foobar/bin/coast: 7: /home/foobar/bin/coast: [[: not found
/home/foobar/bin/coast: 17: /home/foobar/bin/coast: [[: not found
/home/foobar/bin/coast: 7: /home/foobar/bin/coast: [[: not found
/home/foobar/bin/coast: 27: /home/foobar/bin/coast: [[: not found
Downloading a fresh copy of coast...
Created a new coast project in directory myapp
I had to replace #!/usr/bin/env sh with #!/usr/bin/env bash and it worked without error. But then I ran into next issues and I don't know how to fix
foobar@foobar-B85-HD3:~/projects/rubbish/todos$ make db/create
clj -A\:db/create
Exception in thread "main" java.io.FileNotFoundException: -A:db/create (No such file or directory)
Does anybody know what's the reason of problem? Makefile:
.PHONY: test

test:
	COAST_ENV=test clj -A\:test

clean:
	rm -rf target

uberjar:
	clj -A\:uberjar

repl:
	clj -R:repl bin/repl.clj

db/migrate:
	clj -A\:db/migrate

db/rollback:
	clj -A\:db/rollback

db/create:
	clj -A\:db/create

db/drop:
	clj -A\:db/drop

jobs:
	clj -m 

assets:
	clj -m coast.assets

routes:
	clj -m coast.router

sigmaray21:01:13

I'm afraid that coast is not mature enough... I'm Thinking about returning to Compojure

sigmaray21:01:19

One more question, is there Clojujre alternative to activeadmin? https://activeadmin.info/

hiredman21:01:42

what is coast?

Santiago21:01:05

@seancorfield I think I understand now, the issue is here (let [columns [(keys data)], so I have a list inside a vector. How do I get rid of that?

Lennart Buit21:01:46

if you want columns to be a vec instead of a list, you could use (vec (keys data))

Lennart Buit21:01:32

most collection functions in clojure return something list-like so if you were to run (keys {:a 1 :b 2 :c 3}) in a repl you would get (:a :b :c)

Lennart Buit21:01:45

which is a list consisting of :a :b :c

Santiago21:01:07

right. I guess the question here is: is it a good idea to do this inside a function? My idea is to make it general, so that if I pass a different var with different keys, the let bindings will also be different, or do I always have to hardcode the bindings?

Lennart Buit21:01:18

sorry let me check your original problem before talking out of my neck ^^

Lennart Buit21:01:31

Lets go one step back, how would your data look in a clj datastructure?

Lennart Buit21:01:13

I’d assume something like this right:

[{:first-name "Lennart" :last-name "Buit"}
 {:first-name "Santiago" :last-name nil}]
And then you would like to have a CSV with columns first-name and last-name and a row consisting of Lennart/Buit and Santiago/nil. Is my assumption correct?

Santiago21:01:05

my goal is to have a function with an if test that either writes a new csv with headers if the file doesn't exists, or spit

Santiago21:01:13

and just :append

Santiago21:01:23

the thing is I'm still prototyping the structure of the "database", so I wanted to avoid hardcoding the names of the keys in the let statement, if that's possible

Lennart Buit21:01:33

ofcourse that is possible

Santiago21:01:23

that's a good start 😄

Lennart Buit21:01:49

What you could do right, is always store the contents of your CSV in such a vector as I showed right, and then, when writing it back, determine the header, write that followed by the data

Lennart Buit21:01:31

The “determining the header” bit is a bit tricky tho, because you would need to determine all possible keys that could exist in “CSV entries”

Santiago21:01:38

`(defn save-to-file [filename data] (if (.exists (io/as-file filename)) (spit filename (s/join "," [(data :start-time) (data :end-time) (data :duration)]) :append true) (write-csv filename data)))`

Santiago21:01:44

this is what I cooked up

Lennart Buit21:01:52

right, but that becomes tricky when you would add extra keys to your data, then your header wouldn’t match

Santiago21:01:01

but write-csv doesn't work because (keys data) evaluates to a list, and let [columns ['(:key)] doesn't work

Santiago21:01:21

oh yes, that is totally true

Lennart Buit21:01:02

So, why not read the original CSV file, add your new data, determine the new header, and write the concatenated result

Santiago22:01:16

ah I get it now! ok I need to think how I would do that

Santiago22:01:00

but that solves a downstream problem I get the feeling, no the fact that the let bindings have to be "dynamic"

Lennart Buit22:01:30

well, in my approach they don’t. Because you would construct the “header” from the keys of the entries

Lennart Buit22:01:02

let me write it out for you ^^

Lennart Buit22:01:54

(def data
  ;; Assume this comes from some sort of file
  [{:last-name "Santiago"}
   {:first-name "Lennart" :last-name "Buit"}])

(defn determine-header
  [data]
  (let [keys-by-row (map keys data)] ;; These are all keys present in the data, will be ((:first-name) (:first-name :last-name)) for the example
    (apply set/union (map set keys-by-row))) ;; "Merge" these using set union

(defn write-rows
  [data]
  (let [header (determine-header data)]
    ... here you should write some code to write the rows ...))

Lennart Buit22:01:27

This would net you with header being defined as a set consisting of :first-name and :last-name. The rest you should really try yourself!

Lennart Buit22:01:29

I’d suggest grouping the data by the header, and generating rows

Santiago22:01:22

oh I see, this makes sense, cool thank you very much! I'll try thtat

Lennart Buit22:01:43

Good luck and glad I could help!

Santiago23:01:19

(defn write-csv 
  [path row-data]
  (let [headers (determine-header row-data)
        rows (mapv #(mapv % headers) row-data)]
    (with-open [file (io/writer path)]
      (csv/write-csv file (cons headers rows)))))
🙌😄 works thanks again

Anthony Ciacci21:01:35

Has anyone set up in emacs a way for the kill command to skip putting a killed selection on the kill ring if the selection is just an empty string/blank lines?