beginners

Getting started with Clojure/ClojureScript? Welcome! Also try: https://ask.clojure.org. Check out resources at https://gist.github.com/yogthos/be323be0361c589570a6da4ccc85f58f.
soxley 2020-09-30T04:42:15.411600Z

I am evaluating some code in emacs, and the representation of the value I'm getting back does not make sense to me. Can someone tell me what type of data structure #:question{...} and #:category{...} are here?

[#:question{:text "How do you squeeb a thlob?",
            :answer "You have to bibidibop it first"}
 #:category{:title "Technical"}]

soxley 2020-09-30T04:42:51.412100Z

Are they just maps? They seem to behave like maps

soxley 2020-09-30T04:44:02.412800Z

Ok, I used type to figure out the answer - it's a clojure.lang.PersistentArrayMap.

dpsutton 2020-09-30T04:44:29.413Z

❯❯❯ clj
Clojure 1.10.1
user=> (apropos "namespace")
(clojure.core/*print-namespace-maps* clojure.core/namespace clojure.core/namespace-munge clojure.pprint/*print-suppress-namespaces*)
user=> *print-namespace-maps*
true
user=> {:a/b 1 :a/c 2}
#:a{:b 1, :c 2}
user=> (set! *print-namespace-maps* false)
false
user=> {:a/b 1 :a/c 2}
{:a/b 1, :a/c 2}
user=>

dpsutton 2020-09-30T04:45:18.413300Z

its just a shorthand for printing. {:a/b 1 :a/c 2} -> #:a{:b 1, :c 2} rather than repeating the namespace a multiple times it prefixes the map with it

soxley 2020-09-30T04:46:10.413500Z

Aaaah - that makes sense.

dpsutton 2020-09-30T04:46:50.413700Z

and you can turn it on and off as you need with *print-namespace-maps*. (note how i found it with apropos)

soxley 2020-09-30T04:48:02.413900Z

Yes, perfect - thanks! Now that I know what it means, it's fine to have it on, hah.

Jim Newton 2020-09-30T08:37:42.419700Z

There are lots of functions in core.clj which contain what seems to me like declarative information which unfortunately are implemented programmatically. E.g.,

(defn sequential?
 "Returns true if coll implements Sequential"
 {:added "1.0"
  :static true}
  [coll] (instance? clojure.lang.Sequential coll))

(defn sorted?
 "Returns true if coll implements Sorted"
 {:added "1.0"
   :static true}
  [coll] (instance? clojure.lang.Sorted coll))

(defn counted?
 "Returns true if coll implements count in constant time"
 {:added "1.0"
   :static true}
  [coll] (instance? clojure.lang.Counted coll))
It seems to me that these functions should have been created declaratively to allow programs to reason about the types. For example an expression such as (fn [x] (and (sequential? x) (not (list? x)))) sometimes returns true, however (fn [x] (and (list? x) (not (sequential? x)))) will not (if I understand correctly). Why? because clojure.lang.IPersistentList is a subtype of clojure.lang.Sequential, this means that clojure.lang.IPersistentList and (not clojure.lang.Sequential) are disjoint. If that data had been entered a program would be able to do such reasoning.

Jim Newton 2020-10-01T10:06:58.498900Z

the suggestion to use source-fn and parse the output with read-string works pretty well. Here is what I'm able to extract from clojure.core.

([decimal? BigDecimal]
 [seq? clojure.lang.ISeq]
 [fn? clojure.lang.Fn]
 [vector? clojure.lang.IPersistentVector]
 [boolean? Boolean]
 [char? Character]
 [sequential? clojure.lang.Sequential]
 [float? (or Double Float)]
 [set? clojure.lang.IPersistentSet]
 [reversible? clojure.lang.Reversible]
 [map? clojure.lang.IPersistentMap]
 [volatile? clojure.lang.Volatile]
 [var? clojure.lang.Var]
 [string? String]
 [uri? java.net.URI]
 [double? Double]
 [map-entry? java.util.Map$Entry]
 [int? (or Long Integer Short Byte)]
 [associative? clojure.lang.Associative]
 [keyword? clojure.lang.Keyword]
 [tagged-literal? clojure.lang.TaggedLiteral]
 [indexed? clojure.lang.Indexed]
 [counted? clojure.lang.Counted]
 [future? java.util.concurrent.Future]
 [class? Class]
 [sorted? clojure.lang.Sorted]
 [record? clojure.lang.IRecord]
 [ident? (or clojure.lang.Keyword clojure.lang.Symbol)]
 [reader-conditional? clojure.lang.ReaderConditional]
 [integer?
  (or Integer Long clojure.lang.BigInt BigInteger Short Byte)]
 [ratio? clojure.lang.Ratio]
 [delay? clojure.lang.Delay]
 [ifn? clojure.lang.IFn]
 [uuid? java.util.UUID]
 [list? clojure.lang.IPersistentList]
 [rational?
  (or
   (or Integer Long clojure.lang.BigInt BigInteger Short Byte)
   clojure.lang.Ratio
   BigDecimal)]
 [number? Number]
 [symbol? clojure.lang.Symbol]
 [coll? clojure.lang.IPersistentCollection])

Jim Newton 2020-10-01T10:07:52.499100Z

😁

Jim Newton 2020-09-30T08:38:14.420200Z

I'm tempted to write a function to parse core.clj and reverse engineer all these relationships.

Jim Newton 2020-09-30T08:38:32.420400Z

how often does core.clj change?

Jim Newton 2020-09-30T08:43:22.421200Z

Is there a programmic way for me to get the code for a function such as associative? without me having to parse core.clj

2020-09-30T08:46:07.422300Z

there is a macro in clojure.repl namespace (preloaded for you in repl session) (source associative?)

Jim Newton 2020-09-30T08:47:15.422700Z

Would this be available even in a batch clojure?

2020-09-30T08:47:34.423Z

what do you mean?

2020-09-30T08:48:25.424Z

You can look at the commit history yourself. It changed quite rapidly during 2006-2011 time frame, but has slowed down its rate of change quite a lot since then. The Clojure core developers give a lot of thought to keeping later versions of Clojure as backwards compatible as possible with earlier versions.

Jim Newton 2020-09-30T08:48:26.424300Z

if it is part of the repl, I feared it might not be available from a non-interactive session ???

2020-09-30T08:48:43.424700Z

clojure.repl namespace comes with clojure so if you want it β€” add to require

2020-09-30T08:49:30.425800Z

It exists in Clojure, whether you are using a REPL or not. It will print the text of the source code of a function or macro, I think to whatever output stream is the current value if *out*

2020-09-30T08:50:02.426400Z

btw, clojure does not differentiate interactive and non-interactive sessions

Jim Newton 2020-09-30T08:52:42.426900Z

oh, it prints the text, doesn't return it as an s-expression 😞

2020-09-30T08:53:08.427400Z

then use reader to read it into form

Jim Newton 2020-09-30T08:53:20.427800Z

looks like source-fn actually returns the function sexpression

Jim Newton 2020-09-30T08:53:38.428100Z

the code for source is

(defmacro source
  "Prints the source code for the given symbol, if it can find it.
  This requires that the symbol resolve to a Var defined in a
  namespace for which the .clj is in the classpath.

  Example: (source filter)"
  [n]
  `(println (or (source-fn '~n) (str "Source not found"))))

2020-09-30T08:54:55.428800Z

> looks likeΒ `source-fn`Β actually returns the function sexpression no, it will return a text

Jim Newton 2020-09-30T08:55:16.429100Z

Oh, it returns the string? ouch

2020-09-30T08:56:31.430100Z

there is another macro in the same namespace which you might find usefull) (doc clojure.repl/source-fn)

Jim Newton 2020-09-30T08:59:56.431700Z

Is there a way to convert this string to an s-expression with the symbols in the correct namespace? For example, I could bind ns to nil before calling source to have all namespaces printed in long form?????

2020-09-30T09:01:02.432400Z

source-fn return literate source code as it was written in dedicated file

Jim Newton 2020-09-30T09:01:03.432500Z

alas that doesn't work: 😞

clojure-rte.core> (clojure.repl/source-fn 'list?)
"(defn list?\n  \"Returns true if x implements IPersistentList\"\n  {:added \"1.0\"\n   :static true}\n  [x] (instance? clojure.lang.IPersistentList x))"
clojure-rte.core> (binding [*ns* nil] (clojure.repl/source-fn 'list?))
Execution error (NullPointerException) at java.util.concurrent.ConcurrentHashMap/get (ConcurrentHashMap.java:936).
null
clojure-rte.core> 

Jim Newton 2020-09-30T09:02:50.433700Z

what if I bind ns to the namespace of the symbol before reading the text. I think that won't work either because as I understand the clojure reader does not attach namespaces to symbols it reads 😞

2020-09-30T09:03:40.434300Z

maybe you could explain what you want to achieve?

Jim Newton 2020-09-30T09:03:53.434900Z

But anyway, I can start the experimentation with a hacky parser to find out what I want.

Jim Newton 2020-09-30T09:05:37.436600Z

What do I want, I want to reverse engineer the functions like list? and sequential? to find out which types they are a predicate for. E.g., the code for list? is

(defn list?
  "Returns true if x implements IPersistentList"
  {:added "1.0"
   :static true}
  [x] (instance? clojure.lang.IPersistentList x))
I would like to write a function which takes list? as an argument and returns clojure.lang.IPersistentList.

Jim Newton 2020-09-30T09:05:49.436900Z

as list? is a type predicate.

2020-09-30T09:06:16.437200Z

clojure.lang.IPersistentList
this is not a type but interface thow

Jim Newton 2020-09-30T09:07:55.438200Z

more correctly: the symbol clojure.lang.IPersistentList is a type designator. It designates a set of values.

Jim Newton 2020-09-30T09:08:31.438600Z

the value of clojure.lang.IPersistentList is java.lang.Class

Jim Newton 2020-09-30T09:09:21.439600Z

similarly integer? maps to (or Integer Long clojure.lang.BigInt BigInteger Short Byte)

2020-09-30T09:10:37.439700Z

curiouse, how you get that?

Jim Newton 2020-09-30T09:11:45.440400Z

I may be able to find a more correct way later, but using source-fn is certainly enough for a proof of concept. πŸ™‚

2020-09-30T09:12:19.440700Z

proof of concept for what?)

Jim Newton 2020-09-30T09:21:50.442800Z

You can take a look if you like: https://gitlab.lrde.epita.fr/jnewton/clojure-rte It is not yet released explicitly, although the repo is publicly readable. It is a port of a Common Lisp package into clojure. One of the challenges (and one of the most interesting parts of the project) is to impose a simple type system onto the java system of classes as viewed from clojure.

Jim Newton 2020-10-01T10:04:25.498700Z

I was thinking more about an academic-ish conference dealing with clojure programming.

2020-10-01T14:11:55.026100Z

There have been several Clojure conferences, like the Conj, but they tend to be more practitioner focused than academic. But some of the talks do get into the design and/or implementation of some libraries that add significant functionality to Clojure, sometimes in odd ways.

2020-10-01T14:13:30.026300Z

There are conferences like International Conference on Functional Programming, but I think that tends to focus on Haskell and similar languages, but I'm guessing on that as I haven't looked at its accepted papers for quite a while.

2020-09-30T09:36:23.443Z

isn’t that achievable with clojure.spec?

Jim Newton 2020-09-30T09:51:15.443300Z

That's a good question. There is certainly some overlap. rte, however, is based in finite-automata-theory, and strives to minimize runtime checks. It matches sequences WITH NO backtracking.

Jim Newton 2020-09-30T09:51:31.443500Z

as I understand spec is based on backtracking.

Jim Newton 2020-09-30T09:52:41.443700Z

also. If you declare to spec that something is both number and also integer, will spec check both? if not, how does it know whether integer? implies number?

Jim Newton 2020-09-30T09:54:16.443900Z

Here is an application of rte: https://gitlab.lrde.epita.fr/jnewton/clojure-rte/-/blob/master/dsc.md. I'm not sure how you'd do that with spec.

Jim Newton 2020-09-30T09:55:34.444200Z

the overlap of spec and rte is a matter of ongoing research. I'm actually looking for a student to take on that research.

Jim Newton 2020-09-30T09:55:49.444400Z

Having trouble finding a student interested in doing clojure related research.

Jim Newton 2020-09-30T13:35:48.445700Z

another question about so-called private functions, defined with (defn- ...), are they allowed to appear in the expansion of a public macro?

alexmiller 2020-09-30T13:41:19.446500Z

they can, but generally they won't be resolvable

Jim Newton 2020-09-30T14:14:54.447100Z

I get an error loading a file that uses a macro which expands to code which references ensure-fns-index which is private.

Jim Newton 2020-09-30T14:15:35.448Z

hi Alex, sorry I don't understand what you mean by, won't be resolvable....

alexmiller 2020-09-30T14:15:37.448400Z

yeah, that's the "not resolvable" part

Jim Newton 2020-09-30T14:15:57.448800Z

do I have to make public, all functions which appear in the expansion of a macro

ghadi 2020-09-30T14:16:15.449400Z

macros expand into ordinary code, so if ordinary code can't use the private function...

alexmiller 2020-09-30T14:16:28.449700Z

generally, yes

ghadi 2020-09-30T14:17:05.450400Z

forms spliced in by a macro usually become part of the public API

xceno 2020-09-30T14:35:21.452700Z

I came across a bunch of lein projects that seem to easily mix java with clj by adding :java-source-paths to their project.cljand where good to go. Can this be done with tool.deps too? I couldn't find a working example anywhere. I'm asking because it would be just a single java file, and building a separate java project would be overkill right now.

Jim Newton 2020-09-30T14:36:49.452900Z

hmm.. that's surprising. I don't have to like it but I have to accept it.

Jim Newton 2020-09-30T14:36:51.453100Z

πŸ™‚

Jim Newton 2020-09-30T14:38:26.453400Z

OK, can you remind me how to reference a private symbol, such as within a test case?

Jim Newton 2020-09-30T14:44:23.453900Z

I'll put a comment on the docs of defn-` when I understand it well enough to do so.

2020-09-30T14:50:07.454300Z

not out from the box atm but with most recent clojure cli you can craft something yourself consider this β€” https://github.com/EwenG/badigeon/blob/master/API.md#badigeonjavacjavac

xceno 2020-09-30T14:51:42.454700Z

huh sweet, thank you!

alexmiller 2020-09-30T14:58:35.454900Z

you can invoke through the private var, instead of via the symbol

alexmiller 2020-09-30T14:59:16.455100Z

can't say I've ever done that with a macro, but you'd need to emit code that resolved the symbol to the var

Jim Newton 2020-09-30T15:01:58.455300Z

ahh you mean use #'the-name in the macro definition rather than just the-name.

Jim Newton 2020-09-30T15:03:08.455500Z

I have a surface-macro which expands to a lower level macro. I didn't really want to make the lower level macro public as its interface involves knowing about the inner-workings of the system. the public macro is designed for the public.

Jim Newton 2020-09-30T15:05:38.455900Z

how's this? https://clojuredocs.org/clojure.core/defn-#example-5f74a0fce4b0b1e3652d73c7

alexmiller 2020-09-30T15:09:02.456100Z

off the top of my head, I don't that that works with macros

2020-09-30T15:13:11.456300Z

as I understand it compiling java is permanently out of scope for tools.deps itself, but anyone can write a t.d task that compiles java

2020-09-30T15:13:36.456500Z

same goes for nearly any other lein feature / plugin

xceno 2020-09-30T15:22:56.456900Z

Alright makes sense. Thanks!

Stas Makarov 2020-09-30T15:27:58.457200Z

I'm playing with spec in cljs app and can't make :ret work with instrument

(s/def ::int int?)
(defn inc2 [x] "not int")
(s/fdef inc2 :args (s/cat ::int int?)
        :ret ::int)
(stest/instrument `inc2)

<http://humaid.app|humaid.app>&gt; (inc2 "i")
#error {:message "Call to #'<http://humaid.app/inc2|humaid.app/inc2> did not conform to spec.", ...
<http://humaid.app|humaid.app>&gt; (inc2 3)
"not int"
What am I doing wrong?

alexmiller 2020-09-30T15:34:39.457600Z

instrument doesn't check ret specs

alexmiller 2020-09-30T15:35:04.457800Z

https://clojure.org/guides/faq#instrument_ret

Stas Makarov 2020-09-30T15:38:43.458Z

Thanks!

Jim Newton 2020-09-30T16:32:55.458100Z

apparently it doesn't 😞 looks like private functions are half baked. Perhaps it's better just to use a project specific naming convention?

alexmiller 2020-09-30T16:34:08.458300Z

that is the more common answer - foo* or foo-impl or whatever

Jim Newton 2020-09-30T16:34:38.458500Z

πŸ‘:skin-tone-2:

2020-09-30T19:26:36.459200Z

@jimka.issy I do not know if this affects what you are doing, but note that a single JVM object can implement many Java interfaces, not merely one. The JVM relationship between "class A extends class B" is a tree with "java.lang.Object" at the root, but the JVM relationship between "class A implements interface X" is potentially one-to-many, as well as "interface X extends interface Y" is also potentially one-to-many, so the graph of such relationship when including interfaces can be a pretty much arbitrary directed acyclic graph, I believe.

2020-09-30T19:27:35.459400Z

For example:

user=&gt; (source counted?)
(defn counted?
 "Returns true if coll implements count in constant time"
 {:added "1.0"
   :static true}
  [coll] (instance? clojure.lang.Counted coll))
nil

user=&gt; (counted? [1 2 3])
true
user=&gt; (counted? #{1 2 3})
true
user=&gt; (counted? '(1 2 3))
true

dharrigan 2020-09-30T19:47:24.461300Z

So, I have a map that as one of the key values, contains a function. i.e {:foo (fn [] blah-de-blah-blah)}. I wish to invoke this function, and I end up doing this ((:foo my-map)). That doesn't feel right. Is there a better way of invoking that function?

alexmiller 2020-09-30T19:58:38.461600Z

seems fine to me

alexmiller 2020-09-30T19:58:50.461800Z

double left parens always look weird

alexmiller 2020-09-30T19:59:16.462200Z

but you get that with higher order stuff returning fns

dharrigan 2020-09-30T20:01:15.462400Z

np πŸ™‚ thank you πŸ™‚

2020-09-30T20:30:54.464200Z

That is definitely one of those times when you might realize how absolutely significant parentheses are in Clojure (and other Lisps). A lot of people new to Lisps don't immediately realize that adding extra parens changes the meaning of code (unlike, say, a C/C++/Java/Python arithmetic expression on the right hand side of an assignment, where in most cases extra parentheses are redundant but harmless)

2020-09-30T20:33:37.465300Z

everytime on emacs-lisp or another lisps, I stop to think why they used 2 parens on let πŸ˜…, never liked this use-case

2020-09-30T20:35:17.465700Z

Obviously, Rich Hickey didn't like that syntax either πŸ™‚

2
Cameron 2020-09-30T20:42:15.467200Z

while I mostly was exposed to emacs lisp first, I am glad I was exposed to clojure's let first. Likewise never grew to like the other kind, and always have to do a double take when I'm working with them

Cameron 2020-09-30T20:43:56.469100Z

I would say the same about, say, cond, but I think there are cases where I do like the original cond, although if I remember it more had to do with I preferred how I could manipulate it with lispy at times, I forget now

evocatus 2020-09-30T22:07:23.471600Z

Hi! Do you think Luminus is a good framework to start with? I need to make a generic website with database, authentication, a dozen entities and about 50-70 pages.

kennytilton 2020-09-30T22:09:35.471700Z

Yes, this is different from Common Lisp in this way. I always got a kick out of how well CL navigated the duality of contexts.

1
seancorfield 2020-09-30T22:16:29.473600Z

@gr.evocatus Well, the Luminus template includes a lot of moving parts -- a lot of libraries (Luminus isn't a framework) -- so you'll need to understand most of those libraries to some degree in order to build the app. Depending on where you are in your Clojure journey, that might be okay but it also might be extremely challenging.

seancorfield 2020-09-30T22:17:45.475Z

I see a lot of beginners try to get started with Clojure by using Luminus to build a "simple web app" and get horribly stuck -- so I always recommend building a "simple web app" using just Ring, Compojure, and maybe Selmer first so they understand some of the basics.

πŸ‘ 3
seancorfield 2020-09-30T22:18:18.475700Z

If you're reading Web Development with Clojure -- which features Luminus for the examples -- you might be alright.

seancorfield 2020-09-30T22:20:37.476300Z

@gr.evocatus have you looked at https://github.com/seancorfield/usermanager-example (or reitit/integrant version linked from the readme)?

Jim Newton 2020-09-30T22:30:31.476500Z

@hiskennyness hi kenny, I didn't know you were doing clojure. I have lots of questions about things that are confusing in clojure

kennytilton 2020-09-30T22:31:05.476800Z

I’m keeping an eye on you! Yer doin fine.

1
kennytilton 2020-09-30T22:31:32.477100Z

Ping me any time!

Jim Newton 2020-09-30T22:34:11.477300Z

where do you live ? i.e. which time zone?

kennytilton 2020-09-30T22:34:54.477500Z

I am US east coast. Often on line 3-4am, tho. Crash by 9ish

Jim Newton 2020-09-30T22:35:38.477700Z

This is an area of confusion. I need to figure out a way to explain my approach.

Jim Newton 2020-09-30T22:36:11.477900Z

What is the best and friendliest forum for presenting clojure stuff, especially bizarre stuff?

2020-09-30T22:49:35.478600Z

I mean, you can publish a document to Github and send a link to it to #off-topic, or #clojure if it is Clojure-related. I'm not sure that I am the best audience for the work you are doing -- I simply wanted to point out the property of JVM interfaces in case you were unaware of it, since several of the Clojure functions you were asking about check whether the argument implements an interface.

Malik Kennedy 2020-09-30T23:24:00.479600Z

Why when I try to add a dependency (that I know is on maven) I get error about not being able to find artifact? Normal internet works in same enviornment...

Could not find artifact io.parsingdata:metal:jar:7.1.0 in central (<https://repo1.maven.org/maven2/>)
Could not find artifact io.parsingdata:metal:jar:7.1.0 in clojars (<https://repo.clojars.org/>)
This could be due to a typo in :dependencies, file system permissions, or network issues.
If you are behind a proxy, try setting the 'http_proxy' environment variable.))
And by 'normal' i mean like ping / wget / ssh from same shell

Avi Drucker 2020-09-30T23:34:22.480900Z

Hi all! I'm new to Clojure and the community, hope to make friends and learn lots with you all πŸ™‚

🍺 2
1
πŸ‘‹ 8
seancorfield 2020-09-30T23:51:18.481300Z

@mksybr This seems to be because it is a pom artifact and not a jar artifact...

seancorfield 2020-09-30T23:51:34.481500Z

So you'll get this error:

(! 706)-&gt; clj -Sdeps '{:deps {io.parsingdata/metal {:mvn/version "7.1.0"}}}'
Downloading: io/parsingdata/metal/7.1.0/metal-7.1.0.pom from central
Error building classpath. Could not find artifact io.parsingdata:metal:jar:7.1.0 in central (<https://repo1.maven.org/maven2/>)

seancorfield 2020-09-30T23:54:08.482Z

It has two modules, core and formats, so you'll need to depend on those directly I think instead of the pom version...

seancorfield 2020-09-30T23:55:15.482200Z

(! 710)-&gt; clj -Sdeps '{:deps {io.parsingdata/metal-core {:mvn/version "7.1.0"} io.parsingdata/metal-formats {:mvn/version "7.1.0"}}}'
Downloading: io/parsingdata/metal-core/7.1.0/metal-core-7.1.0.pom from central
Downloading: io/parsingdata/metal-core/7.1.0/metal-core-7.1.0.jar from central
Downloading: io/parsingdata/metal-formats/7.1.0/metal-formats-7.1.0.pom from central
Downloading: io/parsingdata/metal-formats/7.1.0/metal-formats-7.1.0.jar from central
Clojure 1.10.1
user=&gt;