Fork me on GitHub
#beginners
<
2020-04-18
>
kimim03:04:43

anyone use clojure as research paper data analysis tools?

andy.fingerhut04:04:14

I would recommend asking in the #data-science channel, as there might be a larger audience of people interested in that kind of thing in that channel.

👍 1
Jim Newton09:04:38

This forces me to parse my own function arguments, which is not pretty:

(defn call-with-rte "docstring"
  [bindings thunk]
  (cond
    (empty? bindings)
    (thunk)

    (empty? (rest bindings))
    (throw (ex-info (format "odd number of values given as first argument of call-with-rte: %s"
                            (first bindings))
                    {:type :invalid-call-to-call-with-rte}))

    :else
    (let [[key value & others] bindings
          *rte-known* (assoc *rte-known* key value)]
     (call-with-rte others thunk))))

Jim Newton09:04:46

is let capable of binding dynamic variables in clojure? Or do I need some other special form for that?

Jim Newton09:04:35

or does let only bind lexical variables?

Jim Newton09:04:09

It looks to me like the following behaves quite differently than I expect. If I have a dynamic variable named *foo* then the following still apparently sees the global value, not the rebound value.

(defn bar [x]
  (cond something *foo* ;; still old global value, doesn't see new *foo* binding
        something-else (let [*foo* new-value] (bar (dec x)))))

andy.fingerhut11:04:24

I haven't tested for certain, but I believe let is only for lexical bindings. If you want dynamic bindings, there is the similar-syntax binding

Jim Newton09:04:38

How can I make the recursive call see the new dynamic binding?

didibus10:04:15

let is only for lexical binding.

didibus10:04:25

For dynamic, you want to use binding

Aron10:04:00

some errors are really hard to debug, what does Uncaught TypeError: Cannot read property 'cljs$core$IFn$_invoke$arity$1' of null mean? In the line it says it is by source-map, it seems not to be a null

Aron10:04:26

I know the js error, but that's not enough right now

Aron10:04:00

I can't even do hot-reload because it's inside react and react complains that it's an unmounted component, have to do manual refresh, despite using figwheel and everything

didibus10:04:15

You have a nil somewhere where it isn't allowed

didibus10:04:36

Seems like it might be you try to call something as a function, but that thing is nil

Aron10:04:48

yeah, some props are not there, would be nice to know how to write specs for props so that I catch if one is nil

Aron10:04:07

but these are nested props in dynamically created components, I have no idea how

Aron10:04:34

I found it, but it's the most frequent bug that I waste minutes on before I find it

didibus10:04:07

Hum, ya I don't know. Unfortunately don't have a lot of experience with react and surrounding libs

Aron10:04:47

I am not sure why would this be specific to react and to its libs.

Jim Newton12:04:11

What are the semantics of memoize with regard to recompilation?

(def f (memoize g))
When I re-evaluate this definition, has the old cache been removed/forgotten?

potetm12:04:46

That’s true for all forms. They get re-set on the var whenever you re-evaluate.

potetm12:04:01

You can prevent this with defonce

Aviv Kotek12:04:02

matplotlib equivalent in clj? vega/oz would be enough? is there something else I should look on? I see some cluttered reddit threads but not much more, ty

hindol13:04:44

Ask in #data-science too.

Jim Newton15:04:05

I can get the ancestors of a class with ancestors : (ancestors Long) returns a set of classes, one of which is java.lang.Number . However (descendants java.lang.number) raises an exception.

Execution error (UnsupportedOperationException) at clojure-rte.core/eval18520 (form-init10469598600043035746.clj:682).
Can't get descendants of classes
Is there a way to find these descendants?

alexmiller15:04:51

There is no way to ask that question in Java

alexmiller15:04:23

Without doing static analysis of “all” classes

alexmiller15:04:37

Which is what ides like Cursive do

Jim Newton15:04:56

Cursive, the IDE?

Jim Newton15:04:56

perhaps there's a way to answer an easier questions. Given two classes, are they disjoint? I was planning to answer the question by finding whether they have a common descendant. my idea doesn't work.

Jim Newton15:04:22

I don't actually need to know what the common descendent is, just whether there is one.

alexmiller15:04:04

If you’re talking concrete classes, then you only need to know whether one is an ancestor of the other

alexmiller15:04:35

If interfaces, then what’s to stop someone from introducing a new interface at any point that implements both?

Jim Newton15:04:41

the question of whether a new class or introduced later doesn't bother me.

Jim Newton15:04:55

but no, I don't know they are both concrete classes. they may be abstract classes.

Jim Newton15:04:09

can I know from clojure whether a class is abstract or not? maybe that could be a workaround. If they are abstract (or interfaces) assume they might intersect, but if they are concrete, determine whether they are disjoint by looking at ancestors

andy.fingerhut16:04:13

Out of curiosity, why do you want to know if two classes A and B are disjoint? (I guess by that you mean that an object cannot be an instance of a subclass of both A and B?)

Jim Newton16:04:37

exactly. given an expression such as (and Integer String) we know this is an empty type. We know this because Integer and String are disjoint. And we for the same reason we know that (and (not Integer) String) is inhabited.

alexmiller17:04:07

Integer and String are also final so they can’t be extended

Jim Newton17:04:38

How can I know whether a given class is final?

andy.fingerhut17:04:04

Should be one of the attributes/flags you see on a class using the Java reflection API.

Jim Newton17:04:54

is there some sort of show-me-the-attributes function in clojure?

andy.fingerhut17:04:18

There is a Clojure wrapper around that (or similar JVM calls) that gets you a Clojure data structure with the same data in it. Looking that up ...

andy.fingerhut17:04:45

Try this in a REPL:

(require '[clojure.reflect :as refl])

andy.fingerhut17:04:55

(print (refl/type-reflect java.lang.Integer))

Jim Newton17:04:05

there is a cider-inspect function, but it doesn't seem to do anything useful.

andy.fingerhut17:04:44

I have no knowledge of Cider with which to suggest anything there.

Jim Newton17:04:25

interesting (refl/type-reflect java.lang.Integer) returns a data structure with a key :flags whose value is #{:public :final}

Jim Newton17:04:43

Is a clojure program free to require clojure.reflect ? or will that fail to work in some environments?

Jim Newton17:04:27

Question. given two classes, one of which is final and one not, then may I suppose they are disjoint whenever the non-final one does not have the other in its ancestors?

Bill Phillips17:04:35

Java does not have multiple inheritance for classes

Bill Phillips17:04:30

So yes. Similarly, (and (not (instance? (type a) b)) (not (instance? (type b) a)))

Bill Phillips17:04:53

instance? would be the idiomatic operator here

Jim Newton17:04:00

Bill, you are supposing I have an object of the type, right? or am I missing something?

Jim Newton17:04:32

I'm trying to do a predictive computation without having an instance. i.e., which will for for any instances of the two types.

Bill Phillips17:04:09

ahh, you are correct. although I think Java’s Class has a method to make the check you’re doing by scanning ancestors

Jim Newton17:04:34

@U010GL90FN0 l two classes are disjoint if they have no common inhabited descendent. And as the previous discussion lead me to know, in java you cannot ask for descendants of a class 😞

Jim Newton17:04:25

The work-around is that in the case of a final class, we know there are no descendants. thus we just need to check whether one is a supertype of the other, via ancestor check.

Bill Phillips17:04:08

but remember: there’s no multiple inheritance

Bill Phillips17:04:29

so if two classes are not ancestors of one another, they cannot have a common descendant

Bill Phillips17:04:18

if neither is assignable from the other, they are disjoint, and so are any subclasses

Jim Newton17:04:48

cool. I saw that function in the code for isa?

Bill Phillips17:04:46

ahh, that looks like the tool you want. much easier

Jim Newton17:04:06

I don't understand the logic. Should I just take your word for it? Or should I try to convince myself that you are right?

Bill Phillips17:04:09

if you like. you seem like someone who prefers to know things for sure. the key thing to know is that, for a given class A, it will have exactly one superclass. Object is the root class

Jim Newton17:04:54

How can I call isAssignableFrom ? The isa? code uses a syntax I don't understand. (. ^Class parent isAssignableFrom child)

Jim Newton17:04:06

OK, here is an example. java.lang.constant.Constable and .Serializable both have no ancestors, but they are superclasses of both Integer and also String. The computation should determine that they are NOT disjoint.

Bill Phillips17:04:13

it looks like isa? works on class instances

Bill Phillips17:04:40

Unfortunately, your specific example is not answerable

Jim Newton17:04:30

what does the isAssignableFrom approach do in the case of Constable and Serializable ?

Bill Phillips17:04:11

isa? looks like a nice bit of sugar on top of isAssignableFrom. So they will accomplish the same thing here

Bill Phillips17:04:13

Let’s take (disjoint? .Serializable com.bphillips.Box) as an example

Bill Phillips17:04:32

Box is my class, I defined it

Bill Phillips17:04:50

it doesn’t implement Serializable

Bill Phillips17:04:10

Serializable is an interface, though. Any subclass of Box can implement it if they want

Jim Newton17:04:24

is Box final? I guess it isn't.

Jim Newton17:04:40

OK, so I understand how to compute disjoint-ness in the case one of the classes is final. The remaining question is what is the best I can do when they both fail to be final.

Bill Phillips17:04:27

well, let’s choose something besides Serializable

Bill Phillips17:04:38

if we choose something that is a class, not an interface, the question is easy to answer

Jim Newton17:04:07

Comparable ?

Bill Phillips17:04:27

classes aren’t interfaces. they’re two distinct concepts in Java

Bill Phillips17:04:16

if you want to refer to both, “type” would be the right word I think

Jim Newton17:04:54

it looks like the (refl/type-reflect java.lang.Comparable) tells me whether the given class is an interface. thats good.

Bill Phillips17:04:04

classes aren’t interfaces

Bill Phillips17:04:07

no class is an interface

Jim Newton17:04:09

ok there are three cases, :final, :interface, and other.

Jim Newton17:04:32

so there are 6 cases for disjoint?` right? some of which are answerable and some not.

Jim Newton17:04:06

So what can I know if one of the two classes is not an interface and also not final ?

Bill Phillips17:04:10

i think there are only four cases: :interface :interface :interface :class :interface :final-class :class :class

Jim Newton17:04:56

btw, (type java.lang.Comparable) returns java.lang.Class so programmatically speaking it is a class.

Jim Newton17:04:28

(type Integer) returns the same thing, as does (type Object) so from the clojure perspective, they are all classes, even if at the java level they are not.

Bill Phillips17:04:34

sure. but that is a detail of the reflection. in Java code, these things are declared by writing either public class MyClass { ... } or public interface MyInterface { ... }. Extending a class is done with extends, extending an interface is done with implements.

Bill Phillips17:04:07

if you abide by this distinction, i can promise you that it will pay dividends in your communications with all who are fluent in Java.

Bill Phillips17:04:53

and this is also why clojure’s decision to name the function to get an instance of Class type rather than class was a good one. 🙂

Bill Phillips17:04:11

(now that I think about it)

Jim Newton17:04:32

so there are three cases for a and three cases for b , :final, :interface, :else. That is 9 cases. if either is :final, we can use isa?. that leaves 4 cases. (other, interface), (other, other), (interface, interface), (interface other)

Jim Newton17:04:07

I think for (other,other) I can use isa? because of the promise of single inheritance. nothing can inherit from both unless one is already a subclass of the other.

Bill Phillips17:04:21

anyway, to get back to the four categories: * :interface :interface - These are never disjoint. Nothing prevents someone from creating a new class at runtime that implements both interfaces. * :interface :class - Same as above. Nothing prevents someone from creating a new subclass that implements the interface. :interface :final-class — Disjoint if (isa? interface final-class) (edit: I mean (not (isa? interface final-class)) :class :class — Disjoint if (not (or (isa? a b) (isa? b a))

Jim Newton17:04:31

That leaves 3 (other,interface),(interface,other), and(interface,interface)

Bill Phillips17:04:24

And if the right hand is an interface and the left hand is a class, swap them

Jim Newton17:04:28

I think it makes sense. I'll try to code it up tomorrow, and see what happens. its almost 20h00 now. time to quit for the day.

👍 1
Jim Newton17:04:57

@U010GL90FN0 thanks for the insight. I'll site (blame) you in the comments of my function, and everyone will send you email if it breaks (grins).

Jim Newton17:04:22

how should I cite you?

Bill Phillips17:04:28

hope i was of some help! i have NEVER explained Java’s notion of classes to someone who was introduced to OO elsewhere, or through clojure’s reflection first, so this is interesting. 🙂

Bill Phillips17:04:49

Bill Phillips is fine. @jingibus on github

Jim Newton17:04:05

Java's concept of type of class is bizare to someone coming from lisp.

Bill Phillips17:04:12

It is very, very restricted, by design. Classes are very concrete and inflexible. But it is helpful to understand them, because every instance in Java is built on that foundation

Jim Newton17:04:22

for me a type is a set of values. the type might or might not have a name, and might or might not be specifyable.

Jim Newton17:04:50

OK. gotta go. thanks again for the help.

Bill Phillips20:04:01

made a mistake above, see edit

Jim Newton09:04:41

I have discovered 4 kinds of class flag sets. I don't understand the difference, as I don't know java. Maybe these make sense to a Java programmer???

clojure-rte.core> (:flags (refl/type-reflect  String))
#{:public :final}
clojure-rte.core> (:flags (refl/type-reflect  Object))
#{:public}
clojure-rte.core> (:flags (refl/type-reflect  Number))
#{:public :abstract}
clojure-rte.core> (:flags (refl/type-reflect java.lang.CharSequence ))
#{:interface :public :abstract}
clojure-rte.core> 

Jim Newton09:04:03

what is a public class which is neither abstract not final ?

Jim Newton09:04:17

are all interfaces also abstract?

Jim Newton09:04:49

Also two very different classes Object and clojure.lang.PersistentList are both marked as :public but neither :final nor :abstract

Jim Newton09:04:20

what does it mean to be non-abstract? and non-interface? does that mean it is possible to instantiate it?

Jim Newton16:04:36

in terms of code optimization this means that if we have already checked that an object is an Integer and discovered that it is then we know a subsequent check for whether it is a String can be omitted as it is guaranteed to evaluate to false .

andy.fingerhut16:04:03

Is your goal to use such knowledge for code optimization?

andy.fingerhut17:04:12

I am not certain, as I have not delved deeply into this kind of thing before, but the JVM has some fairly dynamic features, and I think it may be possible to reload a class later after it has been loaded once before, and if so, the answers might be different for a later loaded version of the class.

andy.fingerhut17:04:30

That might be beyond what you are hoping to handle, if it is true.

Jim Newton17:04:30

semantically it of course does not hurt to check (instance? String x) discover that it is true and thereafter also check (instance? Integer x) , but a static analysis should be able to determine that the latter will be false

Jim Newton17:04:29

how can I call the next most applicable method in a multimethod?

phronmophobic18:04:32

the code for multifns isn’t too bad. as alex said, you could ask for method of choice (using https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/MultiFn.java#L144) and remove it. alternatively, you could copy the https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/MultiFn.java#L161 and change it to return the second best method

Jim Newton09:04:24

Yes, but that only solves the problem the first time. If that second method then wants to call call-next-method, then I'd want it to work as well. In CLOS any method may call call-next-method and it will work, provided there is a next method. There is a function next-method-p if the method wants to know whether there is such a next method.

Jim Newton17:04:46

i.e., the one that would have been called if the current method didn't exist

alexmiller17:04:06

You could remove the one it found and call it again :)

Jim Newton10:04:43

removing it and calling again would only work the first time, but it wouldn't work when that method wants to call call-next-method. 😞

Jim Newton10:04:38

CLOS is beautiful for the programmer, but a horror for the compiler implementor.

Jim Newton10:04:45

so what's the pattern using clojure multimethods to allow a method to contribute to the return value, or for a method based on runtime logic to decide whether it can compute the result, or delegate to next less specific method?

alexmiller17:04:24

But really, there is no easy way to do that

piegie22:04:06

Hi! Does anyone know of any boards or w/e where people/beginners share sth they've recently written and more experienced people take a look at it for feedback or sth to that effect?

phronmophobic23:04:57

there’s the #code-reviews channel, but it’s usually slow. I haven’t tried it, but something like https://exercism.io/tracks/clojure may be of interest. you can ask in #exercism if you want a take from someone who actually has tried it

runswithd6s03:04:50

This is really great! Thanks @U7RJTCH6J