Fork me on GitHub
#clojure
<
2017-06-03
>
qqq03:06:27

is there a way for core.match to match all LISTs of length-3 where first element is 'foo ?

qqq03:06:35

i.e. '(foo 2 3), '(foo (+ 2 3) 4)

qqq03:06:54

match seems to dislike literal symbols in the lhs of match

rads05:06:32

@qqq:

user=> (match ['(foo 2 3)] [(['foo a b] :seq)] [a b])
[2 3]

michaellindon15:06:55

is there a way to dissoc multiple keys in a nested map simultaneously?

rauh15:06:49

@michaellindon (dissoc m :a :b :c :d)

michaellindon16:06:00

@rauh does this work for a nested map? {:a {:b {:c 1}} :d 3}

john16:06:20

:b and :c would be misses, if that were m. But they'd be dissoced anyway, since they hang off :a

john16:06:16

For nested maps, keys may be duplicate. So you'd need to convey some structure.

john16:06:32

ie, at what nesting location you mean by :b in {:a {:b {:c 1}} :b 3}

michaellindon16:06:48

i found this to be quite a good solution

michaellindon16:06:01

(postwalk #(if (map? %) (dissoc % :a :stuck_out_tongue: :c :d) %) my-map)

john16:06:51

I think specter can do something similar too

michaellindon16:06:38

specter looks cool

dominicm16:06:07

@michaellindon Something I've started to use is this:

(postwalk #(cond-> %
             (map? %)
             (dissoc % :a :b :c :d))
          my-map)
It reduces the if/else branch, and makes the flow more uniform

michaellindon17:06:39

@dominicm looks good, why do you use postwalk and not prewalk?

michaellindon17:06:24

isnt it the case that postwalk does depth first traversal, so that you enter down into nested maps that would be dissoc'd anyway?

michaellindon17:06:41

i started using prewalk instead of postwalk

noisesmith17:06:00

both postwalk and prewalk are depth first, but prewalk updates values on the way down, and prewalk updates them on the way back up

noisesmith17:06:32

because we use immutable data structures it's always necessary to walk back up again recreating the collection (with either)

michaellindon17:06:26

ok thanks 🙂

nadejde17:06:44

@weavejester Hi! Just wanted to say a quick thank you for your help yesterday! Got my project working with a prototype to abstract the bottom DB layer, passing it through a function that returns the handler and with tests using mocked out db functions. Works great! Not added Component in yet as it seems to complex for my simple play project:) Thank you very much for your help yesterday!

michaellindon17:06:11

@noisesmith @dominicm so here is an interesting example, I don't fully understand the differences between prewalk and postwalk, I will read up on them, but there is a difference when the key im dissoc'ing has a value that is very very large. See this for example:

user=> (prewalk #(if (map? %) (dissoc % :a ) %) {:c {:a (iterate inc 1)}})
{:c {}}
user=> (postwalk #(if (map? %) (dissoc % :a ) %) {:c {:a (iterate inc 1)}})
[just hangs here indefinitely]

weavejester17:06:23

@nadejde You’re very welcome. Glad it’s working well for you!

weavejester17:06:42

@nadejde There’s a tool called Shrubbery that can make mocking protocols easier, btw.

noisesmith17:06:57

@michaellindon yeah - because dissoc on the pre-walk avoids ever visiting the children

michaellindon17:06:06

great, thats what i need

noisesmith17:06:15

I think it's still depth first, you just short circuited it..

michaellindon17:06:10

have you ever implemented a branch and bound algorithm? I need to soon and this may come in handy. I need to traverse a tree, but not visit subtrees if a node doesnt satisfy a certain predicate

nadejde17:06:39

@weavejester yeah found the tool and will have a look at using it. First run just wanted to build it manually. Gets my understanding up some levels:) thank you

elena.poot17:06:57

@michaellindon the way I remember it is the prefix (pre/post) tells you whether the node is visited before or after its children. postwalk visits each node after first visiting the children. The root node (top level map) will be the last thing processed. prewalk visits the node before the children. The top level map is the first thing processed. prewalk works for you because it lets you dissoc the children without first visiting them. postwalk would process all the child nodes before doing the dissoc on their parent and throwing them away.

elena.poot17:06:07

And of course in your example above, postwalk will process every member of the infinite sequence produced by iterate before processing its parent node, thus the hang. Whereas prewalk never looks at it.

mobileink18:06:34

is there some switch that must be thrown to preserve quotation marks when printing a clojure form to a string?

mobileink18:06:49

i have code that does this. it works, except when it doesn't, and i can't figure it out.

noisesmith18:06:03

it has to do with a binding called *print-readably* and a multimethod called print-method

noisesmith18:06:35

pr stands for print readable and that's what it does (as in, the form clojure can read again, if possible)

noisesmith18:06:42

and pr-str returns the string that pr would print

noisesmith18:06:50

prn is pr plus a newline

noisesmith18:06:29

in a println, a string will not show with "" around it, inside a prn it will

mobileink18:06:21

ok, i'll bet print-readably is the culprit. my code works for namespaces obtained from the boot fileset, but not if i load the code using require. (this is metaprogramming, reading clojure code from namespaces and printing it to a clojurescript file.)

noisesmith18:06:45

what do you use for the printing?

mobileink18:06:49

sth fairly goofy using interop with a stringwriter i think (ran screaming from my desk an hour ago so can't check). i copied it from somewhere. java io frightens me.

mobileink18:06:52

looking at using pprint/write with code-something whose name i forget.

mobileink18:06:28

pp/code-dispatch. no idea what that does, tho.

noisesmith18:06:50

pprint should be printing things readably, it calls pr (via clojure.pprint/write-out)

noisesmith18:06:38

wait, no, it's more complex than all that

mobileink18:06:55

yeah, actually i do use pprint. whether it preserves quotes seems to depend on how i load the namespaces, so i'm guessing boot fiddles with \print-readably\ or something.

noisesmith18:06:43

but that's a dynamic var, it's setting while loading a namespace can't effect how you print unless you are printing while loading

noisesmith18:06:42

it only effects string output, not how things are read

noisesmith18:06:55

unless you are using pprint while reading the code too? that seems backward

mobileink18:06:54

boot have a fn that gets all the namespaces in the fileset. when i use that, all ok, so i'm just speculating that somehow that fn affects state. or i've inadvertently done so somehow.

noisesmith18:06:01

and how are you getting this source code that you output via pprint?

mobileink18:06:15

i require the ns, then pluck out the vars to which i have added metadata, then print some of the metadata.

noisesmith18:06:16

but that's not source unless you are attaching source code as metadata which is weird...

mobileink18:06:31

starts with a defcomponent macro that interns a var. it takes some clojure forms and prints them to a string, which it adds to the var metadate.

mobileink18:06:52

kooky, but very useful.

noisesmith18:06:32

so you have two possible points of failure: the thing that creates the string that goes on the metadata, and the thing that prints the metadata

mobileink18:06:56

pretty sure its the bit that creates the metadata string. once it's created with escaped quotes printing it should always work, i would think.

mobileink18:06:14

anyway, thus is helpful, it gives me an idea of where to look.

john18:06:34

@mobileink what's the second way you're getting/requiring the source? Is one version coming from a file and another coming as a string, created and consumed at runtime?

mobileink18:06:48

ok, so my boot task takes a --components arg, which is a set of symbols. #{} means all components, in which case i use boot core's fileset-namespaces to get all nss, which i then search. printing works for that. but if i pass a namespace (foo.bar) or a var sym (foo.bar/baz), i require the nss, and printing does not work.

mobileink18:06:16

also, i put in my namespaces a (println "loading foo.bar"). that gets printed when i pass #{}, but not when i pass #{'foo.bar}

noisesmith18:06:54

perhaps fileset-namespaces is forcing a reload

noisesmith19:06:18

if so, you could see what happens when you add a :reload arg to your requires?

mobileink19:06:11

i'll give that a try. seems odd that that would affect printing, tho.

noisesmith19:06:46

it could be something that only operates correctly when the file is reloaded, due to some sneaky state issue

noisesmith19:06:20

next step being to track down the tricky state issue, ideally

mobileink19:06:10

i'm using log4j, i wonder if that could have something to do with it.

mobileink19:06:13

when i require an ns by name, i can see the log msgs from defcomponent but not the println from the ns.

mobileink19:06:20

with fileset-namespaces i see both. strange. how i hate IO!

mobileink19:06:36

is there a convenient list of clojure state vars like print-readably somewhere?

noisesmith19:06:28

+user=> (apropos #"^\*.*\*$")
(clojure.core/*agent* clojure.core/*allow-unresolved-vars* clojure.core/*assert* clojure.core/*clojure-version* clojure.core/*command-line-args* clojure.core/*compile-files* clojure.core/*compile-path* clojure.core/*compiler-options* clojure.core/*data-readers* clojure.core/*default-data-reader-fn* clojure.core/*err* clojure.core/*file* clojure.core/*flush-on-newline* clojure.core/*fn-loader* clojure.core/*in* clojure.core/*math-context* clojure.core/*ns* clojure.core/*out* clojure.core/*print-dup* clojure.core/*print-length* clojure.core/*print-level* clojure.core/*print-meta* clojure.core/*print-namespace-maps* clojure.core/*print-readably* clojure.core/*read-eval* clojure.core/*source-path* clojure.core/*suppress-read* clojure.core/*unchecked-math* clojure.core/*use-context-classloader* clojure.core/*verbose-defrecords* clojure.core/*warn-on-reflection* clojure.core.server/*session* clojure.java.browse/*open-url-script* clojure.java.javadoc/*core-java-api* clojure.java.javadoc/*feeling-lucky* clojure.java.javadoc/*feeling-lucky-url* clojure.java.javadoc/*local-javadocs* clojure.java.javadoc/*remote-javadocs* clojure.java.shell/*sh-dir* clojure.java.shell/*sh-env* clojure.pprint/*print-base* clojure.pprint/*print-miser-width* clojure.pprint/*print-pprint-dispatch* clojure.pprint/*print-pretty* clojure.pprint/*print-radix* clojure.pprint/*print-right-margin* clojure.pprint/*print-suppress-namespaces* clojure.spec/*coll-check-limit* clojure.spec/*coll-error-limit* clojure.spec/*compile-asserts* clojure.spec/*explain-out* clojure.spec/*fspec-iterations* clojure.spec/*recursion-limit*)

noisesmith19:06:36

and if you are messing with *out* to output your string to file (eg with-out-str) I would not be surprised if this was swallowing printlns accidentally

noisesmith19:06:26

(but not logging)

mobileink19:06:45

i feel much better now. spent about 3 hours this morning beating my head against this one.

noisesmith19:06:29

alternate - maybe more accurate

+user=> (->> (all-ns) (map ns-publics) (mapcat vals) (filter (comp :dynamic meta)))
(#'clojure.core.server/*session* #'clojure.java.shell/*sh-dir* #'clojure.java.shell/*sh-env* #'clojure.java.browse/*open-url-script* #'clojure.pprint/*print-suppress-namespaces* #'clojure.pprint/*print-pretty* #'clojure.pprint/*print-pprint-dispatch* #'clojure.pprint/*print-radix* #'clojure.pprint/*print-miser-width* #'clojure.pprint/*print-right-margin* #'clojure.pprint/*print-base* #'clojure.core/*print-namespace-maps* #'clojure.core/pr #'clojure.core/*2 #'clojure.core/*verbose-defrecords* #'clojure.core/*print-level* #'clojure.core/*print-length* #'clojure.core/*default-data-reader-fn* #'clojure.core/*1 #'clojure.core/*data-readers* #'clojure.core/*e #'clojure.core/*clojure-version* #'clojure.core/*3 #'clojure.java.javadoc/*core-java-api* #'clojure.java.javadoc/*feeling-lucky-url* #'clojure.java.javadoc/*local-javadocs* #'clojure.java.javadoc/*remote-javadocs* #'clojure.java.javadoc/*feeling-lucky* #'clojure.spec/*recursion-limit* #'clojure.spec/*coll-error-limit* #'clojure.spec/*explain-out* #'clojure.spec/*fspec-iterations* #'clojure.spec/*coll-check-limit* #'clojure.spec/*compile-asserts*)

noisesmith19:06:58

since oddly some earmuffed things are not dynamic

mobileink19:06:20

thanks. that should really be a list-globals or sth like that in core.

leobm19:06:41

can anyone help me with plumatic Schema ? I do not really unterstand the conditional function ? I get a ConditionalSchema when I call the conditional function but this Schema acts not like a normal Schema. e.g.I can not use it as value in another Schema. Do I have another options when I want have a conditional sub shema for my base schema by an value of the base schema ?

noisesmith19:06:46

I use conditional schemas inside other schemas

noisesmith20:06:53

oh wait maybe I don't...

noisesmith20:06:50

@leobm it should just work

+user=> (require '[schema.core :as s])
nil
+user=> (def C (s/conditional :a {:a String} :b {:b Number}))
#'user/C
+user=> (s/check C {:a "hi"})
nil
+user=> (s/check C {:a 1})
{:a (not (instance? java.lang.String 1))}
+user=> (s/check C {:b 1})
nil
+user=> (s/check C {:b "hi"})
{:b (not (instance? java.lang.Number "hi"))}
+user=> (def C2 {:m C})
#'user/C2
+user=> (s/check C2 {:m {:a "hi"}})
nil
+user=> (s/check C2 {:m {:a 1}})
{:m {:a (not (instance? java.lang.String 1))}}

noisesmith20:06:48

#(constantly true) is a function that returns a function that returns true if called

noisesmith20:06:52

maybe this isn't what you wanted?

noisesmith20:06:40

(#(constantly true)) -> a function ((#(constantly true))) -> true

leobm20:06:50

it was only for the test.. normally I want check a value from the base schema.

noisesmith20:06:47

I don't see what your example is doing that mine isn't

noisesmith20:06:50

and mine works

noisesmith20:06:58

are you sure you mean to be using defschema? I've literally never needed it, and I don't see what it adds to your code is shown

noisesmith20:06:43

oh - never mind, it's just def plus some metadata

leobm20:06:40

I want a conditional schema check by the type

noisesmith20:06:40

when I change #(constantly true) to (constantly true) that error goes away in your example by the way

noisesmith20:06:38

do you actually get this error with real code?

noisesmith20:06:53

that second example only fails because :type needs to be on the address

noisesmith20:06:58

but address doesn't allow :type

noisesmith20:06:25

the conditional needs to check the thing it describes, not the parent of the thing

noisesmith20:06:04

if the conditional is based on the :type of the person, the conditional should be in the person, not in the address

noisesmith20:06:55

I usually handle things like this by having a base schema, with separate definitions that each assoc variant requirements to the schema data

noisesmith20:06:04

and giving each one a distinct name

joelsanchez20:06:49

Sometimes I need to apply a series of ad-hoc functions in sucession to a value, I naturally use the threading macro for this, but it is kinda ugly

joelsanchez20:06:58

A better way?

joelsanchez20:06:39

(I intend to avoid ((fn [v] )) )

joelsanchez20:06:20

Of course I can define those macros in the namespace but they are only useful in that situation

joelsanchez20:06:14

Another example:

noisesmith20:06:12

why not make those fns defns?

joelsanchez20:06:45

That would be the obvious solution indeed, but I didn't want to pollute the ns with good-only-for-this functions

noisesmith20:06:55

alternatively, use as-> instead of ->

noisesmith20:06:06

and then they don't even need to be fns

noisesmith20:06:52

(as-> {} m (if-not ....) (if-not ...) (reduce ...))

noisesmith20:06:11

since it's always named m, just eliminating the outer layers in the current code will work

joelsanchez20:06:27

Reading about as-> right now, looks like the solution

joelsanchez20:06:41

Yep, thank you 🙂

joelsanchez20:06:58

rewrites everything with as-&gt;

john20:06:58

Also could be used

john20:06:56

Pass the same variable to a sequence of functions?

john20:06:06

Oh, I guess that doesn't thread the result though

noisesmith20:06:09

that's not what is wanted here

john20:06:25

disregard 🙂

joelsanchez21:06:23

juxt is nice but as-> is what I needed

nikki21:06:19

yoooooo as-> is awesome

nikki21:06:28

thank u for enlightening us

nikki21:06:46

slowly humanity is discovering itself through clojure

fbielejec21:06:21

I bumped into a following problem while using the component library - whenever a given component depends on another, the associated dependency in the system map does not release it's resources (i.e. is not stopped) on 'stop-system'. I would assume that both lifecycle methods work in the dependency order and call start / stop for each component and its dependencies in a tree traversal of the dependency graph. I haven't yet looked in detail, but I made a simple application that demonstrates the problem (call lein test to reproduce): https://github.com/fbielejec/component-app

gmercer22:06:59

@fbielejec

mkdir test/app && mv test/system_tests.clj test/app/

noisesmith22:06:27

start doesn't change the input, it returns a new system

noisesmith22:06:41

calling stop on the original asks it to stop something that was never started

noisesmith22:06:37

on line three you create a running system with (start sys) but it goes out of scope and you never bind it

gmercer22:06:34

they are asking about the exact opposite

noisesmith22:06:08

right, but what I'm saying is that line 3 has a bug, with a real system it would be a resource leak

noisesmith22:06:34

and line 1 shows what real code does, and exposes the problem - that the system still has the resources in it that stop should have cleared up

gmercer23:06:02

Should their Handlers record null out both of the dependencies ?

gmercer23:06:05

(assoc this :handlers "still here" :database database)
and
(assoc this :handlers nil :database nil)