Fork me on GitHub
#beginners
<
2021-01-03
>
euccastro00:01:23

or you could use that generator to unpredictably shuffle a vector/array of integers mapping to the range AA000 to ZZ999, as you had in mind. they're fewer than a million, so keeping them in memory is doable

ackerleytng04:01:29

trying to build an uberjar with depstar - I'm getting

clojure -X:depstar uberjar :jar MyProject.jar
2021-01-02 20:48:09.772:INFO::main: Logging initialized @2905ms to org.eclipse.jetty.util.log.StdErrLog
Execution error (FileNotFoundException) at java.io.FileInputStream/open0 (FileInputStream.java:-2).
-X:depstar (No such file or directory)

ackerleytng05:01:03

seems like i needed to update clojure

Vincent Cantin05:01:53

Yes, the -X option is a recent addition to Clojure CLI

seancorfield06:01:43

@U8P40TFSR As the depstar README says: Note: these instructions assume you have at least version 1.10.1.727 of the Clojure CLI installed

seancorfield06:01:24

clj-new is the same: requires at least 1.10.1.727

ackerleytng06:01:47

oh thanks! missed that

ackerleytng05:01:14

when building an uberjar, is the app supposed to be executed? the guide [here](https://github.com/seancorfield/depstar#basic-usage) suggests using :replace-deps , but when I try and build the uberjar, it fails, and the error messages suggest that some dependencies are missing

Vincent Cantin05:01:45

Did you add the depstar alias in your config file? in which one? Please copy it here so we can help.

ackerleytng05:01:07

:aliases {:uberjar
           {:replace-deps {seancorfield/depstar {:mvn/version "2.0.165"}}
            :replace-paths ["src/clj"]
            :exec-fn hf.depstar/uberjar
            :exec-args {:jar "MyProject.jar"
                        :aot true
                        :main-class project.core}}}

Vincent Cantin05:01:47

here, you should use the alias uberjar instead of depstar because that’s how you named it.

ackerleytng05:01:00

oh?? isn't the alias just a name?

ackerleytng05:01:39

let me try that again

ackerleytng05:01:05

thanks! with that config, I did clojure -X:uberjar and I'm getting an error finding mount , but mount is in my dev/ directory - did i use :replace-paths correctly?

Vincent Cantin05:01:34

I never used :replace-paths and did not find its documentation on depstar’s page.

seancorfield06:01:31

@U8P40TFSR If your app depends on things that you would need to provide aliases for, you need to tell depstar what those aliases are.

noisesmith06:01:38

> when building an uberjar, is the app supposed to be executed? perhaps unrelated to your error, but a very common misunderstanding is that clojure doesn't have a "compile mode" - if your def has a side effect, it will run while compiling the file

👍 3
🔖 3
seancorfield06:01:06

See this section of the README:

As of depstar 2.0, the classpath is computed from the system and project deps.edn files. If :repro false, the user deps.edn file is also used. This is intended to correspond to the CLI's -Srepro option that ignores the user deps.edn file. If you need to adjust that classpath, based on aliases, you can supply a vector of aliases to the :aliases exec argument of depstar.

seancorfield06:01:35

I suspect you have an alias (maybe :dev?) that adds dev/, you need to specify :aliases [:dev] (or whatever that alias is).

ackerleytng06:01:41

I added dev/ to :paths in the deps.edn and i was going to :replace-paths when building the uberjar

ackerleytng06:01:36

do you recommend removing dev from :paths and then adding it using an alias for dev purposes?

seancorfield06:01:39

If something needs to be in your final app, it probably shouldn't be under a separate alias -- it should be in your core :paths value (and you wouldn't use :replace-paths).

ackerleytng06:01:57

i only need the stuff in the dev/ directory for dev, so it shouldn't be in the final app

seancorfield06:01:59

(it's very rare that you would ever need :replace-paths)

dpsutton06:01:02

including dev in an uberjar just sounds weird to me

seancorfield06:01:34

Agreed. But it sounds like you have stuff in your main code that refers to things that are in your dev folder -- which doesn't sound right @U8P40TFSR

dpsutton06:01:07

> I'm getting an error finding mount , but mount is in my dev/ directory can you explain what you mean in this sentence?

dpsutton06:01:19

what does finding mount mean?

ackerleytng06:01:31

I think it could be because i originally put dev/ in :paths, which puts it in the final app.

dpsutton06:01:12

sure. what does "finding mount" mean?

dpsutton06:01:32

and how is mount in your dev/ directory

ackerleytng06:01:20

oh wait mount is a dependency in my ~/.clojure/deps.edn and [mount.core :as mount :refer [defstate] referenced in dev/user.clj

dpsutton06:01:09

that's a bit strange. if you depend on mount, add it as a dependency. seems strange to have that only in dev and not throughout the app. not sure what its purpose is there

ackerleytng06:01:14

in my app, i start jetty from main directly

seancorfield06:01:31

Well, if your uberjar is failing because it's looking for mount then, yup, it should be a core dependency in the project. I can't imagine how you'd build an app that only uses mount at dev time -- it's kind of intrusive with its global state (which is why I won't use it).

ackerleytng06:01:32

but i use mount for development so i can stop jetty and restart it

seancorfield06:01:17

If you really think you're only using mount at development time then you absolutely do not need to use mount at all.

dpsutton06:01:27

but if mount isn't sprinkled throughout the app, aren't you just calling a single start and stop on the server? if its not really dealing with dependencies its just an alias for the start and stop of the server

seancorfield06:01:32

You can easily stop/start jetty directly.

ackerleytng06:01:39

ohh i see. would it be like (def server (run-jetty ...)) and then if i need to stop it, do (.stop server)?

dpsutton06:01:22

yeah. i'm guessing that's what you have in your dev namespace right?

dpsutton06:01:39

(defstate ...)

ackerleytng06:01:27

yup that's what i have!

ackerleytng06:01:29

thanks i'll remove mount

seancorfield06:01:44

Remove mount completely from your memory 🙂

Rowan Barnard06:01:36

Hi everyone and I wish a happy new year to all 🙂 I've been working through the book Living Clojure but I'm now stuck on the chapter where we mix cljs code with clj code - I can't get the cljs repl to run - I enter the line the book tells me lein trampoline cljsbuild repl-rhino on the Windows commandline and it tells me Syntax error (FileNotFoundException) compiling at (cljsbuild\repl\rhino.clj:1:1). Could not locate cljs/repl/rhino__init.class, cljs/repl/rhino.clj or cljs/repl/rhino.cljc on classpath. Any ideas what I might be doing wrong?

dpsutton06:01:44

i think the rhino repl was removed from clojurescript recently (ish). That's a pretty old style to get up and running

dpsutton06:01:08

one possibility is that it should work if you use the version of clojurescript that's in use in the book

dpsutton06:01:06

i see a repo from the author working through one of the examples at https://github.com/gigasquid/cheshire-cat which specifies a clojurescript version [org.clojure/clojurescript "0.0-2371"]

dpsutton06:01:56

from github i see that was released on october 9, 2014 and is so old that all of the tooling around it is very out of date. the tutorial itself might still be valid but i haven't seen it. the author's very interesting and done some of my favorite exploratory and fun coding (chemical computing: https://gigasquidsoftware.com/chemical-computing/index.html)

seancorfield06:01:04

I didn't think Living Clojure was that old, but I've sort of lost track of when various books were released at this point...?

seancorfield06:01:56

April 2015. Wow. Almost six years ago!

seancorfield06:01:38

Given my recent experience, coming back to cljs after last looking at it in 2014, things have really changed in the cljs world...

Rowan Barnard06:01:05

Ah OK thanks dpsutton, sean, might try specifying the same clojurescript version as is in the book then so hopefully that should work or I will need to figure out how to do it the modern way

Rowan Barnard06:01:41

I didn't know how to get started with a ring server and mixed clj/cljs with deps.edn so just followed along with the book's Leiningen instructions also, would be nice to know how to do it with deps.edn if there is anything easy I can look at?

dpsutton06:01:25

i'd check out figwheel main's documentation and look for a template with it built in

Rowan Barnard06:01:14

OK thanks, I'll have a look at that 😉

seancorfield06:01:49

@flyingpython I am just getting started with ClojureScript (it's all so different to when I last looked at it that I'm a beginner all over again), and I'm liking Figwheel Main, and as you know I'm using deps.edn. I don't have a combined front + back end app together yet but I'm working on getting something basic together that I'll probably use as a model for what I need to build at work...

seancorfield06:01:21

I'll put it up in a public repo when I have something working end-to-end.

seancorfield06:01:42

(and of course I'm making this all work with Reveal and Atom/Clover)

Rowan Barnard06:01:43

OK that sounds promising Sean, not sure if I'll be able to understand it though?

seancorfield06:01:11

Happy to talk you through it, once I get it all up and running 🙂

Rowan Barnard06:01:44

OK thank you very much, I will look forward to having a look at it 😉

Rowan Barnard07:01:16

At this point in the book I just need something equivalent to lein ring server and getting a ClojureScript REPL up and running (especially if I can do this with Clover/Chlorine) I've been using Chlorine and deps.edn config throughout the book until I got to this chapter as I was unsure how to translate it from Leiningen to deps.edn and socket REPL setup

seancorfield07:01:52

@flyingpython Figwheel is pretty easy to use with deps.edn and the Clojure CLI.

seancorfield07:01:57

I used a figwheel-main-template, told it I wanted a --reagent app. Then clojure -M:fig:build and I was up and running.

Rowan Barnard07:01:26

:thumbsup: That's great; I like easy!

seancorfield07:01:56

(then I added re-frame and converted it from Reagent to re-frame; next I plan to add an http lib so I can call from the front end to the back end I'll build)

seancorfield07:01:40

It is on GitHub but I haven't updated the readme at all so it's not accurate. I'm still poking at tooling and figuring out how best to work with this new-to-me ecosystem 🙂

seancorfield07:01:21

I have updated my dot-clojure files to work with figwheel and reveal tho'... (and I updated that readme to cover some of this)

Rowan Barnard07:01:11

OK, sounds cool, just drop a line on the Chlorine channel or something like that when you have it updated and I'll have a look though I'll probably look soon anyway for lack of patience 😃

ackerleytng07:01:24

would people recommending having a single deps.edn for both frontend and backend?

dpsutton07:01:26

i don't think there's a mechanism to have two. so yes

ackerleytng07:01:38

how should i set up paths? the paths are mostly different, right?

Rowan Barnard07:01:01

Hmm, I've seen projects with more than one deps.edn in them though - maybe the other deps file was just an old artifact they weren't using anymore though if it is indeed the case you can't use more than one

dpsutton07:01:09

you could do src/frontend and src/backend. leads to some awkward bits when you have shared code

dpsutton07:01:22

@flyingpython if they had more than one deps.edn, what were the filenames?

ackerleytng07:01:43

oh i meant :paths in deps.edn

ackerleytng07:01:53

figwheel seems to be expecting paths defined in :paths, which means when i build the uberjar i have to override paths...? does that sound right?

noisesmith00:01:17

there should be no trace of figwheel in the uberjar - figwheel is a dev time tool and in your final artifact you should just have the javascript that cljsbuild outputs

ackerleytng00:01:59

yup! my deps.edn file has both frontend and backend stuff in it. i think i figured it out, here's my final deps.edn https://github.com/ackerleytng/gowherene/blob/master/deps.edn

Rowan Barnard07:01:19

I can't remember the filenames as it was in the past I saw it, they were in different folders in the project though, I assume the filenames were both deps.edn as I am pretty sure that is what I saw but could be wrong given the fallibility of human memory and all

Jakub Zika07:01:03

@flyingpython this is a nice & relevant book about clj / cljs integration (lein, shadow-cljs, raegent and re-frame,..). Still in beta though. https://pragprog.com/titles/dswdcloj3/web-development-with-clojure-third-edition/

dpsutton07:01:26

ah. yeah i've seen that. and a top level one that uses the sub projects with :local/root. an example is chui: https://github.com/lambdaisland/chui

seancorfield07:01:30

Figwheel should only care what is on the classpath when you run it -- which you can control with aliases.

Rowan Barnard07:01:43

OK thanks for the recommendation, I would prefer one with deps.edn though as that is what I've mostly been what I've been using though and I prefer it once I got started, Leiningen is easier to jump in and start with, but I find with deps.edn it seems less magical to me as to what is going on

seancorfield07:01:08

It's certainly reasonable to have :client and :server aliases that specify different paths (and you can still have shared code -- specified in both aliases' :replace-paths or :extra-paths (I'd probably use the latter and have the main :paths just be the shared code).

seancorfield07:01:02

And when you build the (backend) uberjar, just tell depstar to use :aliases '[:server]'

seancorfield07:01:00

And for the front end: clojure -M:client:fig:build should work for development (and clojure -M:client:fig:min for a "prod" build, if I'm reading the figwheel template right).

seancorfield07:01:41

And then a separate REPL to run the server: clj -M:server -r (plus whatever other aliases you want).

seancorfield07:01:02

(for me, the only quirk would that my dev tooling assumes it can write a single .socket-repl-port file into the project, so I would probably spin up both the client and the server together via figwheel and my :dev/repl alias while developing)

seancorfield07:01:12

(something like clojure -M:client:server:reveal:test:fig:build:dev/repl I think, maybe with :add-libs as well depending on whether I thought I might want to add new dependencies after starting my REPL)

dpsutton07:01:10

goodness that's quite an incantation 🙂

seancorfield07:01:43

Easy enough to hide via a shell script or a bash alias 🙂

seancorfield07:01:14

I think my main REPL startup command at work has even more aliases in it. At least they compose nicely 🙂

Rowan Barnard07:01:37

@dpsutton OK yeah, I think like that lamdaisland example but I see there's a simple example on the https://clojure.org/guides/deps_and_cli page under "Using local libraries" they include part of their program as a library which has it's own deps.edn so I am thinking you can use as many deps.edns as you like so long as the source code and deps files are in their own separate folders

seancorfield07:01:24

OK, I'm out for the night. I'll try to carve out some time tomorrow to add a server component to my little re-frame repo and write up the readme so it's all up-to-date.

dpsutton07:01:29

yeah. its quite readable. and for sure a little alias or shell script would fix it

Rowan Barnard07:01:19

OK good night Sean, thanks for the help 😉

seancorfield07:01:21

(now that I've incorporated a lot of the individual pieces into :dev/repl and it adapts to whatever is on your classpath, my dev setup is a lot easier!)

Rowan Barnard07:01:40

Oh that sounds great!

dpsutton07:01:45

i do wish cider worked with socket repls. alas

seancorfield07:01:11

Once they have side-loading, that should be easy to do.

seancorfield07:01:21

Chlorine/Clover side-load unrepl over a socket REPL (and Christophe was working with Bug on doing something similar with nREPL I believe).

flowthing08:01:38

FWIW, nREPL already has a sideloader, but it can’t inject itself over a socket REPL yet. Here’s the GitHub issue for it: https://github.com/nrepl/nrepl/issues/96

caumond08:01:49

hi guys, I don't know where to ask. I'm working with toolnamespace/refresh function. It seems to be broken, no file modification is detected anymore. Don't know what to do, where to look. I remove main from my profile, as some advise.

caumond08:01:31

Just in case, I restart my repl, started with a fresh copy of my repo....

caumond10:01:56

I did not understand all the subtlety, but it appears my refactor-nrepl / cider-nrepl and tools.namespace were conflicting.

gibi10:01:11

hi, how can I retrieve vectors instead of lists when using partition ? Thanks

caumond10:01:10

Hi, in my understanding you can't directly, but you can retransform them to vector

caumond10:01:02

(map #(into [] %) (partition 2 [1 2 3 4]))

🙌 6
caumond10:01:30

is it answering your question?

caumond10:01:46

Yees, I got it, you're the first I help !

Michaël Salihi10:01:32

@francesco.losciale Or more concisely (map vec (partition 2 [1 2 3 4]))

👍 6
william11:01:20

question on clojure.spec: when I do something like (s/def ::myspec ...) what am I actually defining? What trips me is that that's not a variable, so I'm not sure how I should use it from another file. Doing something like:

(s/conform (s/coll-of myfile/myspec) collection)
doesn't work (use of undeclared var)

caumond11:01:59

when you declare s/def ::myspec you fullfill a https://clojure.org/guides/spec#_registry which key is the keyword

caumond11:01:29

your example does not because s/coll-of does not seem to call the keyword

william11:01:02

thanks, and how would I refer to that spec to conform some data in another file?

caumond11:01:40

try

(s/def ::tst int?)
(s/conform (s/coll-of ::tst) [1 2])

william11:01:18

I got it now! Your example wouldn't work for me, but :myfile/myspec would! It's just a keyword!

william11:01:30

thanks for the help @caumond! 🙂

caumond11:01:37

to refer an external keyword, you need to specify the full qualify name

caumond11:01:43

yes, that's it

caumond11:01:57

have a look also to ::myfile/myspec syntax

caumond11:01:26

very helpful to use :as in your require`

caumond11:01:51

(require [myfile :as m])
::m/myspec

caumond11:01:21

it was my last wednesday breakthrough, (;p

william11:01:35

hahaha, very good points, thanks again 🙏

caumond11:01:54

no pb, us guys are sleeping, so early I have opportunities to appear knowledgeable

😂 6
Christian11:01:37

Normally, when I have a hash-map, I can look up if a key exists and I can see all values. With a transient hash-map that does not work. How would I solve this?

(vals {:a 1 :b 2})
;; => (1 2)

(vals (transient {:a 1 :b 2}))
; Execution error (IllegalArgumentException) at robot-name/eval29220 (form-init8682869554046594837.clj:59).
; Don't know how to create ISeq from: clojure.lang.PersistentArrayMap$TransientArrayMap

noisesmith00:01:56

transients don't replace hash-maps, they are an optimization for code that builds up hashmaps, so they lack many of the read-oriented features

roelof11:01:59

I think Im complicating things here to solve this challenge

; Write a function, validate, which will check that :name and :glitter-index are
; present when you append. The validate function should accept two arguments: 
; a map of keywords to validating functions, similar to conversions, and the
; record to be validated.
 
(def validation {:name validate-name
                 :glitter-index validate-index})

(defn validate
  [validators suspect]
   (and (get suspect key) ((get validators key) (get suspect key))))

pavlosmelissinos12:01:25

key is undefined, what is it meant to represent?

roelof12:01:39

a record looks like this {:name: "John Doe" , glitter-index: 2}

roelof12:01:12

so as far as I see it , key is first name and then glitter-index

pavlosmelissinos12:01:10

Yup that makes sense. What's your question then?

roelof12:01:50

my question is that I think Im overcomplicating things. Am I right with that ?

roelof12:01:17

as far as I see if I have to check if the keywords are there and if they are not empty

pavlosmelissinos12:01:13

(Besides any errors in logic) your solution is not valid clojure because key is unbound. It does seem a bit too complicated but to be honest I can't tell where you're going with it, so I can't answer your question, sorry. The description is a bit vague too (e.g. what does when you append refer to?) Anyway, the exercise seems to consist of two parts. Why don't you try completing them one by one? Leave the second argument aside and try to focus on the first sentence: > Write a function, validate, which will check that :name and :glitter-index are > present [in a record]

roelof13:01:55

I will try that

roelof15:01:55

hmm no luck

roelof15:01:04

(defn validate
  [validators suspect]
    (every?  #(contains? validators %) suspect))


  
(validate [:name] {:name "toto"})

roelof15:01:23

it gives now false where I expect to be true

pavlosmelissinos15:01:27

Keep simplifying the requirements until you can come up with a solution and build up from that! e.g. a good starting point could be: > Write a function that has a single input (the record) and checks that :name is present in that record

roelof15:01:53

I hope I did now a good job

roelof15:01:59

; Write a function, validate, which will check that :name and :glitter-index are
; present when you append. The validate function should accept two arguments: 
; a map of keywords to validating functions, similar to conversions, and the
; record to be validated.

(defn validate
  [validators suspect]
    (every?  #(contains? suspect %) validators))

roelof15:01:06

the functions that the text is talking about

(def conversions {:name identity
                  :glitter-index str->int})

(defn convert
  [vamp-key value]
  ((get conversions vamp-key) value))

pavlosmelissinos16:01:04

yup, you're halfway there

pavlosmelissinos16:01:08

contains? is not very idiomatic for key lookup in maps (and it throws people off when it's applied to lists/vectors), get is more natural

roelof16:01:41

oke, changed it and why am i half way there ?

pavlosmelissinos16:01:56

validators needs to be a map, not a vector

pavlosmelissinos16:01:36

> a map of keywords to validating functions

roelof16:01:41

hmm back to the book

(defn validate
  [validators suspect]
    (every?  #(get suspect %) validators))


(defn validate-name[] true)

(validate {:name validate-name} {:name "toto"})

roelof16:01:45

gives now false

roelof16:01:33

and now I Cannot check for :name alone

roelof16:01:44

it has to have a second thing into it

pavlosmelissinos16:01:22

that's not a map

roelof16:01:47

it is not ?

roelof16:01:52

now im confused

roelof16:01:17

I learned that a map look like this : `

{:key "value"}

roelof16:01:26

and I have used that as far as I know

pavlosmelissinos16:01:15

Nevermind, you're right

roelof16:01:27

ok, no problem

roelof16:01:10

I also thought you mean this :

(validate {:validator [:name]} {:name "toto"})

roelof16:01:37

but then I think I need to rewrite this one

(defn validate
  [validators suspect]
    (every?  #(get suspect %) validators))

pavlosmelissinos16:01:07

The validator needs to be a map of keywords to functions

pavlosmelissinos16:01:00

so it needs to look more like the first version (`{:name validate-name}`) and less like the second (`{:validator [:name]}`)

roelof16:01:13

(defn validate
  [validators suspect]
    (every?  #(get suspect %) validators))


(defn validate-name[] true)

(validate {:name validate-name} {:name "toto"})
but then I wonder why this is given false

roelof16:01:32

the name is there and the validate function gives also true

pavlosmelissinos16:01:08

every? works with sequences

roelof16:01:43

got it I think

roelof16:01:50

(defn validate
  [validators suspect]
    (every?  #(get suspect %) (validators key)))


(defn validate-name[] true)

(validate {:name validate-name} {})

pavlosmelissinos16:01:45

this works but here's the thing

pavlosmelissinos16:01:53

what's the point of the validator functions?

pavlosmelissinos16:01:11

shouldn't you be using those to validate the values?

roelof16:01:27

to see if the name is according to a certain thing

roelof16:01:49

yep, but the challenge is not saying what the name should do to be valid

roelof16:01:55

or I have to make things up

roelof16:01:36

I could make code to say it has to be a string and longer then 4 characters but that is made up

roelof16:01:52

no idea if that is a problem or I have to freedom

pavlosmelissinos16:01:33

it's an exercise isn't it? it's up to you

pavlosmelissinos16:01:06

You can also move the logic of get to the validator function

pavlosmelissinos16:01:27

but then it wouldn't exactly check for membership

pavlosmelissinos16:01:22

e.g. should this be true or false? (validate {:name validate-name} {:name nil})

roelof16:01:12

I would say false

pavlosmelissinos16:01:23

btw this is the difference of contains? and get as well

pavlosmelissinos16:01:16

(contains? {:name nil} :name) => true but (get {:name nil} :name) => nil

roelof16:01:22

got a bug somewhere

(defn validate
  [validators suspect]
    (every?  #(get suspect %) (validators key)))


(defn validate-name[name]
  (and (string? name) (> (count name) 3)))

(validate {:name validate-name} {:name "aa"})
this gives true but 2 is smaller then 3 so it should be false

pavlosmelissinos16:01:25

you're not calling the validator function anywhere

pavlosmelissinos16:01:47

you need to apply the function to the value of the record

pavlosmelissinos16:01:24

(every? #(get suspect %) (validators key)) this does not work anymore

pavlosmelissinos16:01:28

also what do you think (validators key) does?

roelof16:01:32

I thought that

roelof16:01:07

I thought I get the key like name out of it

pavlosmelissinos16:01:50

key works on map entries, not whole maps

pavlosmelissinos16:01:24

you can get the full key set of a map with keys

roelof16:01:05

then there is another problem

roelof16:01:16

(defn validate
  [validators suspect]
    (every?  #(get suspect %) (validators keys)))


(defn validate-name[name]
  (and (string? name) (> (count name) 3)))

(validate {:name validate-name} {:name "aa"})

roelof16:01:30

gives still true where I expect to be false

pavlosmelissinos16:01:37

you're not using validate-name anywhere

pavlosmelissinos16:01:57

how do expect it to be false? 😛

roelof16:01:43

pff I have to think about that one. I thought (apply validators keys) could help me but it does not

pavlosmelissinos16:01:51

ok so the values of validators are functions that you need to apply to the values of the record

pavlosmelissinos16:01:25

apply is a figure of speech, I'm not referring to the actual clojure function

roelof16:01:52

and Im still thinking I have to do something with this part #(get suspect %)

pavlosmelissinos16:01:05

yup, that's the culprit

roelof16:01:37

im thinking that that one give me the function

pavlosmelissinos16:01:23

#(get suspect %) gives you the value of the record for a particular key

roelof17:01:02

and then im stuck how I can pass the name or the glitter-index to it

pavlosmelissinos17:01:28

one problem at a time

pavlosmelissinos17:01:09

So if the key is :name, what do you want instead of just #(get suspect %) ?

pavlosmelissinos17:01:20

to actually use the validator

roelof17:01:37

normally I do somehing like this : (validate_name "John")

pavlosmelissinos17:01:26

Correct but now you don't have access to the actual function name.

pavlosmelissinos17:01:40

You have the key of the validator instead (`:name`), how would you get the function using that?

roelof17:01:14

using get ?

pavlosmelissinos17:01:00

yes, how would you write that in code?

roelof17:01:07

so something like (get validators(get suspect %)

pavlosmelissinos17:01:45

(get suspect %) gives you the value that you want to validate so that's one thing on its own

pavlosmelissinos17:01:13

you can get the function in a similar way: (get validators %)

pavlosmelissinos17:01:14

So now that you have the function and its parameter, how do you build the actual call?

roelof17:01:46

So I need

(every?  #(get suspect %) (get validators %) (validators keys)))

pavlosmelissinos17:01:37

the syntax of every? is (every? f coll)

roelof17:01:00

I saw it when I tried that one

roelof17:01:27

(defn validate
  [validators suspect]
    (and  (every?  #(get suspect %) (validators keys))(every?  #(get validators %) (validators keys))))
  
still do not work as I expect

roelof17:01:45

be back after dinner/supper

roelof17:01:52

thanks so far

pavlosmelissinos17:01:24

No offense, but it seems to me like you try random things when you get stuck. Try to understand why stuff doesn't work first instead.

roelof17:01:03

i take no offense

roelof17:01:21

I was thinking about two clauses and combine them with a and

roelof17:01:47

so the keys must be there and the validating must return true

roelof17:01:02

otherwise the record is not valid

roelof17:01:38

(and  (every?  #(get suspect %) (validators keys)) (every?  #(get validators %) suspect)))

roelof17:01:07

looks better to me but no everything is false and the validate function is still not called

roelof17:01:35

Still think I miss some knowlegde what the brave book is trying to teach me

pavlosmelissinos17:01:42

I can't follow your train of thought

roelof17:01:11

we have 2 things to test if the record is valid

pavlosmelissinos17:01:22

what you want to do is: 1. for every key in validators 2. validate the value of record for that key

roelof17:01:26

1. the keys schould be there

roelof17:01:47

2. test if the value of the keys is valid according to a function I made up

roelof17:01:22

1. is done by this piece (every?  #(get suspect %) (validators keys)) , Right

roelof17:01:36

2 is stil something I think I miss a piece

pavlosmelissinos17:01:53

you might not need 1

pavlosmelissinos17:01:09

because if the key isn't there the validation will also fail

pavlosmelissinos17:01:49

but that's another story, let's keep it for now

pavlosmelissinos17:01:03

ok, try this out:

(and  (every?  #(get suspect %) (validators keys)) ;; key exists
      (every?  #((get validators %) (get suspect %)) (keys validators))) ;; value is valid

pavlosmelissinos17:01:31

the syntax is really awkward (it's not how I would have done it) but it works

pavlosmelissinos17:01:12

You can try implementing a saner alternative using merge-with or reduce-kv

pavlosmelissinos17:01:39

merge-with is probably the most straightforward

pavlosmelissinos17:01:16

there's also the "dumb" version:

(defn validate
    [validators suspect]
    (and
     ((:name validators) (:name suspect))
     ((:glitter-index validators) (:glitter-index suspect))))

roelof17:01:38

I could even been

(defn validate
  [validators suspect]
    (every?  #((get validators %) (get suspect %)) (keys validators)))

pavlosmelissinos17:01:22

yes that skips the first check

pavlosmelissinos17:01:17

but it's done implicitly by the validator so in practice it's the same

roelof17:01:32

I saw it when trying

👌 3
roelof17:01:19

I hope I can find out how reduce can make this easier to read

pavlosmelissinos17:01:24

merge-with and reduce-kv will not necessarily make it easier on the eye

pavlosmelissinos17:01:49

But they will allow you to break it down into parts

roelof18:01:35

oke, reading now the page where reduce-kv is explained

roelof18:01:27

I hope im on the right track

(defn validate2
  [validators suspect]
  (reduce-kv (fn [v s] ??? ) {} validators))
I still have to figure out what must be placed instead of the ??

pavlosmelissinos18:01:46

the fn takes 3 params

pavlosmelissinos18:01:11

see the examples

roelof18:01:40

moment, you mean with k the key and with v the value

pavlosmelissinos18:01:53

m k and v are conventions, you don't have to call them that but it helps you understand which is which

pavlosmelissinos18:01:58

see the examples

roelof18:01:53

yep, I have them before me if I try to make this work

roelof18:01:26

I have this now :

(defn validate2
  [validators suspect]
  (reduce-kv (fn [s k v]  ) {} suspect))

roelof18:01:06

where s is the suspect , key is the key of the key I want to test and v is the validation function

pavlosmelissinos18:01:04

you can't choose what k and v will be, they will be drawn from the last argument (suspect in your case)

roelof18:01:27

I know I try to explain my thought process

pavlosmelissinos18:01:04

oh ok, go on then

roelof18:01:33

now I could check if the key exist

roelof18:01:47

so rewrite this part: (every? #(get suspect %) (validators keys))

roelof18:01:44

chips, stuck again

roelof18:01:50

wait a minute, if key is the key of a suspect for example the name then that is the k now

👍 3
roelof18:01:59

so I think I can do something like this : (if #(k (vl keys) .... )

roelof18:01:01

nope, this is more then I can chew now

(reduce-kv (fn [vl k v] (if #(k (vl keys) #(get vl % k ) )   ) {} suspect))

roelof18:01:43

but nested # are not allowed

roelof18:01:09

and this looks better

roelof18:01:17

but give a function

roelof18:01:45

I need a break

roelof18:01:51

this is given nill

roelof18:01:57

(defn validate2
  [validators suspect]
  (reduce-kv (fn [vl k v] (if #(k (vl keys)) (#(get vl %) k) false )) {} suspect))

roelof18:01:58

Right now I very lost on what is what

roelof18:01:23

every? #((get validators %) (get suspect %)) (keys validators)))

roelof18:01:37

the first part #((get validators %) will be #(get vl %)

roelof18:01:39

and the part get suspect%) is #(k (vl keys)

roelof18:01:30

so both would be #((get v1 %) (k (vl keys)

roelof18:01:48

I make somewhere a big thinking error :

(defn validate2
  [validators suspect]
  (reduce-kv (fn [vl k v] (if #(k (vl keys)) #((get vl %) (k (vl keys)) false ))) {} suspect))

(defn validate-name[name]
  (print name)
  (and (string? name) (> (count name) 3)))

(validate2 {:name validate-name} {:name "aaaa"})

roelof18:01:18

still give a function so somewhere I forget a argument

roelof18:01:36

and I do not see where

roelof19:01:40

can you give me a hint @UEQPKG7HQ

roelof09:01:08

or is this what you are looking for :

(defn validate2
  [validators suspect]
  (reduce-kv (fn[acc k v]
               (and acc                            ;; The previous keys were validated
                    (contains? suspect k)   ;; the suspect contains the key in question
                    (v (suspect k))))            ;; the value of that key in the suspect validates according to the validator function
             true validators))                    ;; you want to check all validators, so you reduce over them

 (defn validate-name[name]
  (print name)
  (and (string? name) (> (count name) 3)))
I made this with some help of another person

pavlosmelissinos10:01:43

Are you sure? How did you test it?

roelof10:01:51

with this in repl

(validate2 {:name validate-name} {:name "a"})
;; => false


(validate2 {:name validate-name} {:name "aaaaa"})

roelof10:01:44

and this two give the right answer

👌 3
roelof11:01:08

do you experts agree ?

caumond11:01:16

@christiaaan, I don't know too much about transient but it seems they are not compatible with all operations

caumond11:01:31

usually, you have a x! version of operators

teodorlu13:01:17

I have a type: (defrecord Point [x y]) How can I get a list of all the protocols Point implements?

teodorlu13:01:58

(ancestors Point)
#{clojure.lang.Counted java.lang.Iterable java.util.Map java.io.Serializable
  clojure.lang.IObj clojure.lang.IRecord clojure.lang.Associative
  clojure.lang.ILookup clojure.lang.IMeta clojure.lang.IPersistentCollection
  java.lang.Object clojure.lang.Seqable clojure.lang.IKeywordLookup
  clojure.lang.IHashEq clojure.lang.IPersistentMap}
✔️

teodorlu13:01:21

now, which one lets me do :keys [x y] destructuring? :thinking_face:

teodorlu13:01:32

user=> clojure.lang.ILookup
clojure.lang.ILookup
user=> (doc clojure.lang.ILookup)
Syntax error compiling var at (REPL:1:1).
Unable to resolve var: clojure.lang.ILookup in this context

teodorlu13:01:21

Where's the best place to find docs about protocols and interfaces from Clojure core and clojure.lang? https://clojurians.slack.com/archives/C053AK3F9/p1609680670002700?thread_ts=1609680257.001800&amp;cid=C053AK3F9

popeye14:01:05

I have input which gives out put in below way

(filter some? [[7 6 8] 3 4 nil nil)
([7 6 8] 3 4)

popeye14:01:29

how can i get destructing out put like (7 8 6 3 4)

Max Deineko14:01:45

I suggest flatten

🙌 3
popeye14:01:32

@UEQPKG7HQ I ran this

(flatten [ 5 6 {:a "v" :b "a" } nil 4 nil nil 5 nil :a [ 2 3] ])

popeye14:01:28

the result is expected, it did not destruct the map, but it destructed vector.. Is still fine right?

3
pavlosmelissinos14:01:23

All that matters in the end is whether your solution gives you the expected result. In an exercise like this I think it's fine but in real world problems, when flatten is the most obvious solution then there's a good chance something is wrong with your data model.

👍 6
Harley Waagmeester15:01:02

you might try (flatten .......)

Harley Waagmeester15:01:45

i.e. (flatten (filter some? [[7 6 8] 3 4 nil nil))

Harley Waagmeester15:01:54

lemme try it here..

Harley Waagmeester15:01:02

(flatten (filter some? [[7 6 8] 3 4 nil nil]))

Harley Waagmeester15:01:41

flatten is an old trick from lisp

andy.fingerhut15:01:16

The main caution about flatten is that if you have anything more deeply nested than that, it usually flattens more than you want.

flowthing16:01:38

There’s also the faintly JavaScripty (flatten 1) etc.

andy.fingerhut16:01:55

In Clojure? Or some 3rd party lib?

Andrew Doolittle16:01:23

Good morning all. My cider repl started printing the entire stack trace every time a function is called and even while I'm typing. This is separate from the regular error stack trace. How can I disable this?

dpsutton17:01:13

i think this is an issue with an older version of CIDER. Its making a call to get the clojure-docs and its failing

Andrew Doolittle17:01:48

I'm on the latest version available on melpa (20210102.631). Never experienced this before and I suspect I enabled it when typing some code while emacs was expecting a shortcut command.

Andrew Doolittle17:01:25

Just noticed I no longer have a *cider-error* buffer even after restarting emacs and my repls.

dpsutton17:01:27

if you evaluate (/ 1 0) and get an error do you then have a buffer *cider-error*?

Andrew Doolittle17:01:39

no, cider-error buffer doesn't come up. Also, M-x nrepl-log-expand-button states: Cannot open doc string file "/home/.emacs.d/elpa-26.3/cider-20200915.1827/nrepl-client.elc Looks like it's looking for the old version

dpsutton17:01:10

strange. can you delete your CIDER version and reinstall? not sure what's going on there but if there's two versions at play it might be really weird bugs

Andrew Doolittle21:01:24

I did a complete reinstall of emacs and CIDER, but I'm still not getting a cider-error buffer. The clojuredocs error still comes up as well.

Andrew Doolittle05:01:35

Despite having updated to the latest CIDER nrepl 0.25, my repl was only using 0.22. After some more research, I seem to have solved my problem by updating my ~/.lein/profiles.clj. I removed references to CIDER as https://jakemccrary.com/blog/2017/08/27/my-current-leiningen-profiles-dot-clj/ stated that the latest CIDER no longer requires you to list dependencies explicitly. Feels like a big DUH after fixing this. Thanks for pointing me in the right direction @dpsutton 🙏

mathias_dw17:01:15

Not sure which channel to ask this in, but since this is such a friendly one: I've been using https://github.com/jarohen/chord and http-kit for websocket stuff for the past few years, and since it always did what it needed to do, I never bothered looking at anything else. But if I go to the latest version of http-kit, things break down, and since chord doesn't seem very active anymore, maybe it's a good time to switch. What do people use for working with websockets (frontend and backend)?

pavlosmelissinos18:01:28

haven't tried it but sente looks like a good fit https://github.com/ptaoussanis/sente

mathias_dw18:01:14

yeah, sente was around already when I chose chord. At the time I found sente was overkill

roelof19:01:20

he. why here a null pointer exception

(defn validate2
  [validators suspect]
  (reduce (fn [vl s] ((get validators vl) (get suspect s ))) false (keys validators)))
 
 (defn validate-name[name]
  (print name)
  (and (string? name) (> (count name) 3)))

(validate2 {:name validate-name} {:name "a"})

dpsutton19:01:25

(Get validates vl) is called with false the first run, presumably returns nil and you invoke that

william20:01:43

how do I do #(nth % 1) in a way that puts % in the last position so that I can use it in a ->> macro? (In haskell it would be something like flip nth )

william20:01:34

I know that I can define it myself, or I could use as-> (but as-> doesn't play along with debux's debug macros). Is there an idiomatic way of writing it for ->>?

R.A. Porter20:01:27

You can also use the -> macro, but that makes it the first argument for the whole thread.

william20:01:16

yeah, the problem is that all of the other step would like the last argument

mathias_dw20:01:45

it's really ugly, but you could do (#(nth % 1))

didibus04:01:37

You don't need to do anything, #(nth % 1) is a function of one argument

didibus04:01:11

(->> [1 2 3]
  (#(nth % 1)))

didibus05:01:37

But in the more general case, you can nest ->> inside -> or use as->

(-> [1 [2 4 6] 3]
  (nth 1)
  (conj 10)
  (->> (map inc)))

didibus05:01:08

As well as do what you did, and wrap it in an anonymous fn (you just need to call the fn as well).

didibus05:01:27

Finally, if you really want a flip, its pretty trivial to implement yourself:

(defn flip [f & args]
  (apply f (reverse args)))

roelof20:01:56

oke, I thought the 3th argument should be the standard value