Fork me on GitHub
#beginners
<
2020-11-03
>
kozmicluis06:11:50

This may be the dumbest question ever but, does having both Leiningen and Clojure CLI Tools installed cause any conflicts?

practicalli-john14:11:29

perfectly sensible question.

dharrigan07:11:25

lots of projects have a project.clj and a deps.edn

practicalli-john14:11:58

@luishendrix92 deps.edn for Clojure CLI tools and project.clj for Leinignen do not have relationship with each other. I've added a deps.edn configuration to leiningen projects before so I could use Clojure CLI tools instead. It is usually just adding the :dependencies from project.clj to :deps in deps.edn , along with any aliases for tools or paths. One caveat, if the code relies on Leiningen plugins, like lein-ring , which injects code into the codebase to be able to run a server, then you would need to add that code to make Clojure Cli tools work. This might cause a conflict with Leiningnen plugins.

oly16:11:27

:validate = ( clojure.core/fn [ % ] ( clojure.core/contains? % :condition ) )
I have the above in a hash map, I want to access parts of the value but I get Don't know how to create ISeq from: clojure.lang.Symbol how can i run (last (last (:validate data))) on the above ?

oly16:11:51

I feel like it should be easy but I am missing something

oly16:11:08

(last (last '( clojure.core/fn [ % ] ( clojure.core/contains? % :condition ) )))

oly16:11:34

I figured out that does what I need, it just does not work with the version inside the hash map

dpsutton16:11:47

lots of quoted stuff going on and a random =. Can you show a bit more concretely what you have? it sounds like you have {:validate (fn [s] (contains? s :condition))} is that true?

oly16:11:29

yeah that's correct, the equals is from cider inspect ๐Ÿ™‚

dpsutton16:11:48

ok. given this map, what would you like to do?

oly16:11:09

I am basically after :condition which last last would give me

oly16:11:00

I understand its because the value is basically a fn just not sure how to make it a list that i can manipulate

noisesmith16:11:11

it's not though, it's a list

dpsutton16:11:10

in my example i've put the key :validate is mapped to a function and at that point its opaque. You can't get into it

oly16:11:32

oh so regex out the value is my only hope at that point

dpsutton16:11:46

if you just have a funtion, no, you cannot regex it either

dpsutton16:11:57

please correct me if you aren't dealing with a function though

oly16:11:16

okay thanks for clarifying well i can str the function

oly16:11:35

(str (:validate data)) for example

oly16:11:55

it seems to give me the string version of it

dpsutton16:11:13

functions are compiled jvm code. they don't have string representations beyond a bit of munged name and an address

alexmiller16:11:54

clojure.repl/demunge may be useful if demunging class names

dpsutton16:11:29

you do not have a function then. can you show some example code of how you're making this map?

noisesmith16:11:44

@dpsutton it's a quoted list

noisesmith16:11:55

that would be a function if it were evaluated

noisesmith16:11:26

that's the only way the inspector would show that

oly16:11:24

it could be a quoted list, but should last not work on a quoted list ?

noisesmith16:11:27

@oliver.marks what's your goal here? what do you want function shaped lists for?

dpsutton16:11:29

is this parsing spec output?

oly16:11:56

yes I am parsing spec, I do know about expound but it's not flexible enough

dpsutton16:11:50

at my last job we had some clever core.match usage to pattern match on those

oly16:11:31

so if its a quoted list should I be able to manipulate it / treat it as data

dpsutton16:11:53

(take 3 (iterate (fn [x] (if (seqable? x) (last x) x)) '( clojure.core/fn [ % ] ( clojure.core/contains? % :condition ) )))
((clojure.core/fn [%] (clojure.core/contains? % :condition))
 (clojure.core/contains? % :condition)
 :condition)

oly16:11:21

so that works like in the example where its quote '() but when it comes from spec it errors on clojure.lang.Symbol

oly16:11:48

which is what i don't 100% do i need to run it through another fn first

dpsutton16:11:35

the error message above is saying it cannot create an ISeq from a Symbol. It sounds like you're calling last on a symbol which obviously can't work

noisesmith16:11:16

there are many function forms that you can't call (comp last last) on without that error

oly16:11:40

I guess its back to using str and regex then for now ๐Ÿ˜•

alexmiller16:11:05

you could use the spec for fn to s/conform the list representing a function

alexmiller16:11:10

it will "parse" it for you

alexmiller16:11:42

user=> (s/conform (:args (s/get-spec `fn)) (rest '(fn [x] (if (seqable? x) (last x) x))))
{:fn-tail [:arity-1 {:params {:params [[:local-symbol x]]}, :body [:body [(if (seqable? x) (last x) x)]]}]}

oly16:11:17

nice I will give that a try and see what happens ๐Ÿ™‚

alexmiller16:11:01

clojure is doing exactly that to verify the spec for all registered spec macros

oly16:11:25

it a shame spec errors using (s/keys) does not store the key that's missing in an easier to access format

alexmiller16:11:14

you can also use spec specs to s/conform a spec :)

alexmiller16:11:58

https://clojure.atlassian.net/browse/CLJ-2112 has some work on spec specs, although really the map data forms in spec 2 are probably more useful as a future direction

Jim Newton16:11:49

question about comparing symbols. I have two symbols. I have required [clojure.spec.alpha :as s] into my namespace. But when I try to compare s/and with clojure.spec.alpha/and using = it returns false. Are these really two different symbols? I thought they were the same symbol? I suspect I'm asking the wrong question, but how can I compare s/and to clojure.spec.alpha/and to get true?

alexmiller16:11:37

they are literally different symbols. you could resolve both and see if they refer to the same var

alexmiller16:11:57

whether s = clojure.spec.alpha depends on your current *ns*

alexmiller16:11:06

so it's contextual

alexmiller16:11:18

if I alias s to clojure.string then ...

alexmiller16:11:14

the namespace object is the one that holds alias mappings and ns is what tells you which namespace object to use for resolution right now

noisesmith16:11:02

@jimka.issy if this helps, there's a hash-map that the namespace owns, that maps from symbol to var, and the "namespace" part of a namespaced symbol is used to decide which map to look in when resolving

alexmiller16:11:57

^^ big picture

Jim Newton16:11:36

This seems to work. I've never used condp before, and I was surprised that I need to quote the clause "tests" ('s/and 's/or), which is not the case with case.

(condp (fn [x y] (= (resolve x) (resolve y))) 'clojure.spec.alpha/and
                        's/and 1
                        's/or 2)

noisesmith16:11:47

case is super weird

alexmiller16:11:02

case works with compile-time constants. b/c they're constants, they don't need to be evaluated

alexmiller16:11:58

a lot of weirdness in case is due to the special circumstances of the switch bytecode it's trying to leverage

noisesmith16:11:57

right - there's so many special-case situations for case that don't apply to the rest of clojure

noisesmith16:11:20

like how it treats lists, and symbols for classes off the top of my head

alexmiller16:11:03

well, if anyone ever bothered to read the docstring...

noisesmith16:11:35

I'm not saying the special cases are secret, just that it has a lot of them

Jim Newton16:11:44

case is normal. Every lisp treats it pretty much the same way. clojure, emacs lisp, scheme, common lisp. No surprises there. That condp looks like case, but acts differently was a surprise. It's clear why the main expression needs to be evaluated, but not yet clear to me why the clauses need to be evaluated. Not exactly clear from the docstring either. At least with a casual reading.

Xavier17:11:16

Hi all. Newbie here ๐Ÿ˜„ I have a spec generator question. I was trying (-> ::expression s/gen g/generate) and I ran into the sample limit issue. ::expression is a recursive spec of simple arithmetic-like calculator with def and if like additions. I have been digging around and it seems my naive use of s/or just makes it worst. I was wondering if anyone has any pointer on how to understand/debug why the generator struggles. (I found s/*recursion-limit* suggestions online, but did not help much). Thanks for your time in advance!

noisesmith17:11:53

@xllora generators are quite naiive, and if your spec has an arbitrary function to test, it will create random inputs until one passes

noisesmith17:11:24

usually I'd use a custom generator with the help of things like gen/fmap to create things the spec actually accepts

Xavier17:11:58

@noisesmith does that mean that the default generator would be generating values for all the leave predicates and then just check if valid?

noisesmith17:11:58

(fmap helps especially if there's two parts of the input data that have to "agree" in some way)

noisesmith17:11:51

@xllora if I understand what your asking yes, it's not clever

noisesmith17:11:18

it looks at the types you accept, and creates things that might fit, and uses yours spec to filter

noisesmith17:11:39

it's not hard to make a spec such that no appropriate example would be created after 1000 tries

noisesmith17:11:44

especially in your case where it sounds like you are parsing an expression language

Xavier17:11:10

I see. Then s/or is not actually selecting a branch and expanding it, but both hence making impossible to satisfy? Yes

(s/def ::data-primitives 
  (s/or :number number?                                                                                 
        :symbol symbol?
        :char char?
        :string string?
        :bool boolean?)) 

noisesmith17:11:34

this two-column output displays very badly in the slack client

Xavier17:11:41

Sorry, jumped the gun accidentally hitting return ๐Ÿ˜ž

๐Ÿ‘ 3
noisesmith17:11:10

I notice from the error message though, it's not ::data-primitives that fails to generate, it's ::expression

Xavier17:11:56

Then there is the usual recursive definition on expression around +, -, ... around it

noisesmith17:11:48

yeah, that's your problem, not s/or

noisesmith17:11:17

the error, which you deleted because it was formatted weirdly, was about generating ::expression

Xavier17:11:22

Execution error (ExceptionInfo) at clojure.test.check.generators/fn (generators.cljc:435).
Couldn't satisfy such-that predicate after 100 tries.

Xavier17:11:16

If I understood your point, your suggested is to check fmap to generate a custom generator for the recursive path. I guess adapted versions of something like https://cs.gmu.edu/~sean/papers/treecreation.pdf

noisesmith17:11:47

yeah, more specifically you'd use with-gen to attach a custom generator to the spec for ::expression, and inside that use gen/fmap to create sample expressions that would actually pass the spec

noisesmith17:11:18

the advantage of fmap is it lets you use random generation while still respecting the generator state, so the seed for recreating the failure works

Xavier17:11:25

Interesting. Thanks @noisesmith. Let me go do some more reading ๐Ÿ˜„

ryan echternacht19:11:00

When I boot up my repl, and eval my โ€œmainโ€ namespace (what lein could call core.clj) Iโ€™m getting FileNotFoundExceptions on the other files in my project. If I eval those files then everything is fine. any ideas what I may be doing wrong? I think I have the files/namespace mapping correct

ryan echternacht19:11:24

This project is using deps/clj, not lein

seancorfield19:11:10

@ryan072 Are there any - or _ in any of the filenames and/or namespaces?

ryan echternacht19:11:21

- in namespace, _ in files

seancorfield19:11:24

(also, is this a project we can look at on GitHub?)

ryan echternacht19:11:17

it is, but private

seancorfield19:11:23

And when you say "eval my "main" namespace", what exactly do you mean? (require '[my-project.core])

ryan echternacht19:11:00

specifically, eval the (ns my-toplevel (:require [ โ€ฆ ]))

seancorfield19:11:00

If you're on macOS/Linux, could you share what tree . displays when run inside your project, and also what that complete ns form contains?

seancorfield19:11:19

(it's hard to debug something we can't see ๐Ÿ™‚ )

ryan echternacht19:11:33

(ns yardstick.yardstick-jobs
  (:gen-class)
  (:require [mount.core :as mount]
            [next.jdbc :as jdbc]
            [yardstick.process-channel :as pc]
            [yardstick.fetch-jobs :as fj]))

ryan echternacht19:11:32

I donโ€™t have tree , which is weird because i remember using it in the past

ryan echternacht19:11:01

(ns yardstick.channels
  (:require [clojure.core.async :as async]))
^ one of the other fileโ€™s namespace dec

seancorfield19:11:07

What is the exact FNF exception you're seeing when you try to (require 'yardstick.yardstick-jobs) in the REPL?

seancorfield19:11:35

(or whatever it is you are typing into the REPL that throws an exception)

ryan echternacht19:11:40

โ€ฆ and now it works fine

ryan echternacht19:11:19

whelp, sorry for wasting your time. I recreated the issue like 2x before posting here

ryan echternacht19:11:26

and now everything is peachy

ryan echternacht19:11:18

in general tho, if files match the directory structure under src things should be fine, yes?

noisesmith19:11:47

the actual rule is that the path to the namespace must match a file on classpath or a resource on classpath with a path matching the ns parts

noisesmith19:11:13

src is a classpath root by default

noisesmith19:11:55

I find it somewhat surprising that require would give "file not found" as it can use files, or resources inside artifacts, (or even rare things like URLs...)

noisesmith19:11:40

oh, it does say 'FileNotFoundException", wow

user=> (require 'aokldsjflas.asdfkjlasdf)
Execution error (FileNotFoundException) at user/eval290 (REPL:1).
Could not locate aokldsjflas/asdfkjlasdf__init.class, aokldsjflas/asdfkjlasdf.clj or aokldsjflas/asdfkjlasdf.cljc on classpath.

ryan echternacht19:11:09

That is roughly what I saw

Cas Shun20:11:08

I'm trying to learn core.async and I'm having somewhat of a difficulty understanding what "parking" is and its implications. (I understand blocking). Could someone provide me a quick overview or some search terms that might help me?

alexmiller20:11:48

Parking means that no thread is blocked and work stops until data is available

alexmiller20:11:30

The arrival of data unparks the operation and it is queued to run again

Cas Shun20:11:50

When something is 'unparked', I assume it waits for the next available thread in the pool?

alexmiller20:11:10

Which is why go blocks should never do blocking io (which can block a thread in that fixed size pool)

Cas Shun20:11:01

Thank you Alex