Fork me on GitHub
#clojure
<
2017-10-27
>
neupsh02:10:37

Hello, How do I write a function/macro where I can call another function (not mine) with a quoted structure as an argument. For example:

(another-fun '[:someconfig :val :anotherkey :constkey :myvalue :dynamicvalue])
Where I get the value for :myvalue through some var. I have to construct this quoted expression with most of them as is, but one value evaluated.

neupsh02:10:39

I tried something like:

(defn my-fn [mval] (another-fun `[:someconfig :val :anotherkey :constkey :myvalue ~mval]))
but the syntax quote qualifies those keywords!

seancorfield02:10:39

@neupsh Why does another-fun need a quoted value and not just a regular value?

neupsh02:10:27

@seancorfield it is what the function takes as argument

seancorfield02:10:06

A quoted vector evaluates to just the vector so this ought to work:

(defn my-fn [mval] (another-fun [:someconfig :val :anotherkey :constkey :myvalue mval]))

seancorfield02:10:34

Unless another-fun is doing something very weird and non-idiomatic...?

neupsh02:10:02

@seancorfield hmm, I never thought of checking without the quotes.. I will try it and see how it goes

seancorfield02:10:40

boot.user=> (defn another-fun [v] (reduce + 0 v))
#'boot.user/another-fun
boot.user=> (another-fun [1 2 3 4])
10
boot.user=> (another-fun '[1 2 3 4])
10
boot.user=> (defn my-fun [my-val] (another-fun [1 2 3 my-val]))
#'boot.user/my-fun
boot.user=> (my-fun 4)
10
boot.user=> (my-fun '4)
10

seancorfield02:10:27

See how '4 evaluates to just 4 and how quoting the vector (in the second call) makes no difference.

seancorfield03:10:33

On the other hand, you do need a quote for a list but you can construct it dynamically with list:

boot.user=> (another-fun (1 2 3 4))

java.lang.ClassCastException: java.lang.Long cannot be cast to clojure.lang.IFn
boot.user=> (another-fun '(1 2 3 4))
10
boot.user=> (defn my-fun [my-val] (another-fun (list 1 2 3 my-val)))
#'boot.user/my-fun
boot.user=> (my-fun 4)
10
boot.user=> (my-fun '4)
10

neupsh03:10:50

@seancorfield actually using it directly did not work. let me try to write an actual similar function. I think I may be approaching the problem in wrong way!

neupsh03:10:21

I am writing a small function which can query datomic db for entities using various attributes

neupsh03:10:23

(defn find-user-by[conn attrkw value]
  (let [user (d/q '[:find ?e
                    :in $ ?attr
                    :where [?e attrkw ?attr]]
               (d/db conn) value)]
    (touch conn user)))

neupsh03:10:59

@seancorfield my function looks something like above

neupsh03:10:25

Instead of writing a different function for querying user entity using :user/first-name or :email etc, I thought of writing one and passing :user/first-name dynamically to the datomic q function

seancorfield03:10:35

Ah, and you need the ?e to not resolve, right?

seancorfield03:10:00

(defn find-user-by[conn attrkw value]
  (let [user (d/q [:find '?e
                    :in '$ '?attr
                    :where ['?e attrkw '?attr]]
               (d/db conn) value)]
    (touch conn user)))

seancorfield03:10:18

Quote the symbols you don't want evaluated instead of the whole vector.

neupsh03:10:56

Thanks let me try it 🙂

neupsh03:10:48

@seancorfield Thanks a lot, it worked! I was trying it wrong 😛 Instead of quoting the ones that should be quoted, I was tyring to quote the whole thing and unquote only the attrkw

seancorfield03:10:48

If it gets too frustrating, to keep quoting bits of it, remember that you can do stuff like

(conj '[:find ?e
        :in $ ?attr
        :where] (assoc '[?e _ ?attr] 1 attrkw))

seancorfield03:10:05

(a vector is associative on its indices so you can just swap in a new value for the _)

neupsh03:10:21

Awesome, I was wondering if I can construct expressions like this. I was not sure if it works when I need everything quoted

seancorfield03:10:45

"It's just data" 🙂

neupsh03:10:46

Thanks again @seancorfield I am calling it a day now

seancorfield03:10:10

boot.user=> (let [query '[:find ?e
       #_=>               :in $ ?attr
       #_=>               :where [?e _ ?attr]]]
       #_=>   (assoc-in query [(dec (count query)) 1] :user/name))
[:find ?e :in $ ?attr :where [?e :user/name ?attr]]
^ @neupsh

seancorfield03:10:23

(although that's a bit horrible really)

fedreg04:10:57

Are there any known issues with clojure.string/replace acting funny?

seancorfield04:10:03

You'll need to be a bit more specific, otherwise the answer will just be "no"...

seancorfield04:10:40

Do you have an example of it "acting funny" @fedreg?

fedreg04:10:28

Sorry.... shot in the dark. Have gotten some null pointer exceptions randomly when I'm definitely just feeding it a string and the function is working just fine in the repl. (clojure.string/replace "123-456-asdf" #"[^0-9]+" "")

seancorfield04:10:16

I think you'll only get NPEs from it if you pass it a nil as the string argument...

fedreg04:10:22

Thanks @seancorfield I just can't seem to replicate that so thought i'd check in the remote chance there was some known issue. There never is but it makes me hopeful none the less.

seancorfield04:10:36

@fedreg I bet if you add an assert on the value you're passing to replace you'll get an assertion failure

seancorfield04:10:46

If you're on Clojure 1.9, you could spec (with s/fdef) the function that calls replace and instrument it and see if you can trap the nil value going in...

fedreg04:10:48

Yes, thx! think I will try that

dpsutton06:10:09

i see clojure.java.time has used ztellman's import vars macro from potemkin so you don't have to remember all of the sub namespaces

hiredman06:10:24

also a single segment namespace, terrible

dpsutton06:10:17

why don't you like that. i haven't run into any pain from that so i'm wondering what to be on the lookout for

hiredman06:10:19

alex had a nice comment on a github issue I saw recently, but I don't recall were

dpsutton06:10:06

ah i'd like to see it. he's a thoughtful commenter

hiredman06:10:24

it is bad technically because then the aot compiled clojure code would end up in the default package, and it is unneighborly because you are inviting name clashes

hiredman06:10:33

unsurpisingly, the people with "contributor" and "owner" badges for that style guide are in the wrong

daveliepmann13:10:51

why "unsurprisingly"? Generally I've found the style guide to be a good rough description of Clojure idiom.

dpsutton06:10:42

awesome. thanks for digging it up

dpsutton06:10:16

was it you that sent the PR with the bruce lee replacement?

dpsutton06:10:59

haha that was great. oh well. i just learned something from the discussion there

dpsutton06:10:06

thanks for bringing it up

pbaille07:10:25

Hi, I've got some core.logic question, i've posted it in core.logic chan but no responses, so I'm trying here: i'm doing something wrong here but cannot find what:

(defn zipwitho [rel l1 l2 l3]
  (conde
    [(== () l1) (== () l2) (== () l3) l/succeed]
    [(fresh [fl1 rl1 fl2 rl2 fl3 rl3]
       (l/conso fl1 rl1 l1)
       (l/conso fl2 rl2 l2)
       (l/conso fl3 rl3 l3)
       (rel fl1 fl2 fl3)
       (zipwitho rel rl1 rl2 rl3))]))

(run 1000 [q]
  (fresh [a b]
    (== q [a b])
    (zipwitho 
      (fn [x y z]
           (l/all
               (fd/in x y z (fd/interval 10))
               (fd/+ x y z)))
       a
       b
       [10 10])))

;=>
([(0 0) (10 10)]
[(1 0) (9 10)]
[(2 0) (8 10)]
[(3 0) (7 10)]
[(4 0) (6 10)]
[(5 0) (5 10)]
[(6 0) (4 10)]
[(7 0) (3 10)]
[(8 0) (2 10)]
[(9 0) (1 10)]
[(10 0) (0 10)])

mnewhook13:10:10

with java interop when instantiating a templated java class is it necessary to pass the template type?

Alex Miller (Clojure team)13:10:08

Java erases generics at the JVM level to raw collection types and that’s what you’re using via Clojure’s java interop

mnewhook13:10:29

so I end up with the following error then which I cannot interpret:

java.lang.NoSuchMethodError: com.badlogic.gdx.graphics.g2d.Animation.getKeyFrame(FZ)Lcom/badlogic/gdx/graphics/g2d/TextureRegion;
	at play_clj.g2d$animation__GT_texture.invoke(g2d.clj:257)
With libgdx 1.9.4 this code worked. With 1.9.5 change it no longer does and the API change was: > - API Change: g2d.Animation is now generic so it can support Drawables, PolygonRegions, NinePatches, etc. To fix existing code, specify the TextureRegion type in animation declarations (and instantiations in Java 6), i.e. Animation<TextureRegion> myAnimation = new Animation<TextureRegion>(...); That API I believe changed from TextureRegion getKeyFrame(float x, b boolean) to T getKeyFrame(float x, b boolean) so its not clear what is causing this error.

Alex Miller (Clojure team)14:10:46

that generic is on the return type, which is not even used when selecting an arity for interop (that’s all on the arguments)

Alex Miller (Clojure team)14:10:03

what is the call you’re making?

mnewhook14:10:17

I filed the stack trace here if that helps. https://github.com/oakes/play-clj/issues/112

Alex Miller (Clojure team)14:10:42

I don’t understand why anything there is different or shouldn’t work

bronsa14:10:27

well the difference is that the signature is now getKeyFramw(FZ)Ljava/lang/Object

bronsa14:10:35

so AOT code will not link with new versions

Alex Miller (Clojure team)14:10:51

yeah, it doesn’t make sense to me why it’s looking for the old one - didn’t look like play-clj was aot’ed

Alex Miller (Clojure team)14:10:25

@mnewhook is your project AOT’ed? and if so, have you cleaned?

bronsa14:10:31

i guess he's AOTing his project

mnewhook14:10:48

ah! yes, that was it. Didn't occur to me that AOT could cause this problem 😞

bronsa14:10:18

@mnewhook usually when you're seeing LinkageError/NoSuchMethodError/VerifyError in clojure, it's caused by AOT compilation

alpox15:10:11

Short, probably stupid question: (partition 5 5 [\space] "cseerntiofarmit on") Why does this not fill the last partition up to 5 elements? Wouldn’t it be supposed to do that when given a pad?

sundarj15:10:27

>>>In case there are not enough padding elements, return a partition with less than n items.

alpox15:10:23

Must have overseen that. Thanks. Is there no simple way to always keep exactly 5 elements and fill the rest with a given pad?

ghadi15:10:35

(partition 5 5 (repeat \space) "cseerntiofarmit on")

alpox15:10:20

@ghadi there we go 😄 thanks! i forgot about that 😕 still new 😄

joshkh16:10:24

this might be a silly question, but is there a way to wipe clean all unknown derivations? something like an (underive) that takes no parameters?

noisesmith16:10:25

@joshkh there’s global-heirarchy

joshkh16:10:32

or maybe i should be working with a hierarchy object, store it somewhere, and wipe it when necessary

noisesmith16:10:44

yeah - that’s much cleaner

joshkh16:10:54

okay, thanks 🙂

hiredman16:10:20

actually using hierarchies isn't exactly well trodden ground

noisesmith16:10:50

@hiredman derive, underive, and defmulti all use them - they just default to the global

hiredman16:10:21

but even derive and underive on the global hierarchy are not very common

bronsa16:10:53

i think in my 7 years of writing clojure i've used derive twice, never underive

hiredman16:10:51

so I am just saying, advice and best practices on using hierarchies(born out from experience) is going to be thin on the ground

joshkh16:10:11

in my scenario i've built a mock file system in the browser from a tabular data source where each row only knows its parent id. when i read in the rows i derive its id with its parent id, and then i can easily grab all descendants without having to mapify or recursively iterate through the rows.

joshkh16:10:01

it felt quicker and more performant, but i guess it's somewhat stateful as well?

hiredman16:10:12

sure, definitely

hiredman16:10:34

you are using a hierarchy to get a mutable map

joshkh16:10:44

what could go wrong!

hiredman16:10:57

you could just use a map in an atom

hiredman16:10:58

(a hierarchy is just a map in a ref, so not all that different implementation wise, but semantics I guess)

joshkh16:10:04

gotcha. it was just an experiment / lazy way to not build and manage a tree myself. in that regards, success. 😉

joshkh16:10:10

thanks for the advice guys

j.kranthi16:10:13

Is there a way for us to override a protocol implementation on a type coming from a transitive library namespace?. Lets say I am consuming a library and it defined to look at a specific field on a Avro type and I want myself to override that lookup for my own usecase.

phronmophobic17:10:16

extend-protocol is just a macro around extend which is just a function

phronmophobic17:10:27

so if you have the protocol, the type you would like to override, and the implementation, you should be able to just pass that to extend at runtime

j.kranthi17:10:36

@smith.adriane The library already has a extend protocol on the type and I want to make sure for my project my own extend protocol on the same type overrides the implementation coming from the library and moreover the protocol itself is defined in the library.

phronmophobic17:10:52

when you say for your own project, does that mean your code will use one implementation and in the same program, the library’s code will use a different implementation for the same protocol?

noisesmith18:10:48

protocols are not locally bindable like that - there’s only one implementation possible per concrete class

noisesmith18:10:18

if your implementation is defined later, it replaces a previous definition for that specific class (if it existed)

j.kranthi18:10:58

I want to completely replace the definition. how do I ensure that my implementation is the one that is picked up at runtime?

phronmophobic18:10:02

I just tried a dummy example and it looks like you get IllegalArgumentException class MyType already directly implements interface MyProtocol for protocol

phronmophobic18:10:34

when you try to replace the implementation

phronmophobic18:10:45

(defprotocol MyProtocol
  (f1 [_]))


(defrecord MyType []
  MyProtocol
  (f1 [_]
    1))

(clojure.core/extend MyType
  MyProtocol
  {:f1 (fn [_]
         2)})

phronmophobic18:10:30

but

(defprotocol MyProtocol
  (f1 [_]))


(defrecord MyType []
)

(clojure.core/extend MyType
  MyProtocol
  {:f1 (fn [_]
         1)})

(clojure.core/extend MyType
  MyProtocol
  {:f1 (fn [_]
         2)})

j.kranthi18:10:43

yea, in the above example, lets say the first extend is in namespace1 and second extend(override) is in namespace2 and a third namespace uses namespace1, namespace2. I don't know if I can guarantee that namespace2 extend is always picked over namespace1. May be there is nothing I can do here but want some input for my usecase.

phronmophobic18:10:34

if you wrap your extend in a function, then you can just call it at the top of your -main

phronmophobic18:10:38

;; namespace 2
(defn do-my-extend! []
  (extend MyType
    MyProtocol
    {:f1 (fn [_]
           2)}))


;; main namespace
(defn -main [& args]
  (do-my-extend!))

phronmophobic18:10:01

the -main will probably run after all the top level code

phronmophobic18:10:27

alternatively, if you have access to the source of the library you’re consuming, it might be worth considering just creating your own fork

j.kranthi18:10:09

Thanks. I will try with the first approach.

qqq19:10:06

EDIT: question moved to #re-frame

ddrbt19:10:22

I want to read and write XML but I see there are clojure.xml, clojure.data.xml and clojure.data.zip to choose from. Does anyone have experience with these? Do they complement each other?

phronmophobic20:10:42

I had to do some xml parsing at some point and ended up using clojure.data.xml. clojure.data.xml can parse lazily. I’m not sure if clojure.xml can also parse lazily and without loading the xml document into memory

phronmophobic20:10:20

seems like clojure.data.xml is a better than clojure.xml option unless you really only need very basic xml parsing functionality

ddrbt21:10:49

@smith.adriane thanks, I’ll give that a spin 😎

mobileink22:10:14

Does programming shape the way you think? A research project: https://twitter.com/leraboroditsky/status/924006274852892672 Comments to #off-topic , please.