Fork me on GitHub
#beginners
<
2020-04-03
>
Michael Stokley00:04:15

i'm mostly concerned about divide by zero exceptions, which it looks like ratios do not prevent. maybe i should use doubles - you can divide a double by zero, looks like.

jumpnbrownweasel00:04:57

@michael740 is this what you're trying to do?:

(/ (+ 20 2) (+ 5 2))
=> 22/7

Michael Stokley00:04:32

that would do it! i do think ratios are not the right tool for me, after all.

jumpnbrownweasel00:04:44

Also see quot which is regular division (not a ratio).

jumpnbrownweasel00:04:16

It rounds to the nearest integer.

hindol05:04:28

Quot truncates, does not round up, only rounds down.

phronmophobic00:04:46

@michael740, it sounds like you’re trying to do algebraic manipulations. maybe something like https://github.com/clojure-numerics/expresso ?

Michael Stokley01:04:51

wow, thanks for pointing me at this!

Michael Stokley01:04:37

i didn't know this existed

aaron-santos04:04:37

I have a cyclical data structure built with Refs that I would like to print. At some points I'd like the print the hex part of ref.toString() without printing the contents. What's the best to access this part Ref?

aaron-santos04:04:47

For example the 0x1662e925 part of #object[clojure.lang.Ref 0x1662e925 {:status :ready, :val true}]

aaron-santos04:04:18

Nevermind, got it (format "%x" (System/identityHashCode my-ref))

mrchrisadams05:04:29

hey folks. I’m trying to parse the XML from a wordpress export to move into blog using cryogen or perun, some nice clojure static site generators. I think I need some pointers in parsing the xml though, as i’m able to follow examples on clojure doc and clojure’s own test to see how to get a single map from a post using the queries in the gist below. However, I’m unable to figure out how to iterate through an xml data structure to do this for the other 150-odd posts available to me - when I try to get the next I get the whole blob of XML, which is no good fo me. I’ve spent a good few hours reading up on how clojure zippers work, and trying various kinds of recursion, loops, and other macros but alas - no dice. I’m defeated by something I could do in pretty quickly in other languages :( You can see my code in the gist below, along with the source xml - how can I work with each post in the xml, to get a map back to write to a text files, or dump in a database? https://gist.github.com/mrchrisadams/cb9b3af65757b9fb9253b0c3cfa1d6cd

Jim Newton09:04:41

What is the correct way to test for a thrown ex-info using clojure.test? At the call site of ex-info I can specify data in a hashmap. With the (is (thrown? ...)) I would like to test the information in that hash map to make sure I'm getting the correct exception information.

andy.fingerhut09:04:54

You can wrap it in a try/catch, assign the exception to a local variable, use ex-data to get the data out, and check whatever part of its contents you wish, potentially using one or more (is (= x y)) expressions.

kelveden10:04:43

And if that proves a bit too much boiler-plate, you can hide it away by extending clojure.test with custom assertions by adding methods to the assert-expr multimethod - see thrown? and thrown-with-msg? themselves for examples.

Jim Newton10:04:28

@andy.fingerhut can you help me construct a try/catch will only catch the exception I designated in the (throw (ex-info ...)) ? And importantly will not accidentally catch any other.

gerritjvv10:04:51

(try (throw (ex-info "mybad" {:a 1})) (catch clojure.lang.ExceptionInfo e (prn (ex-data e))))

👍 1
gerritjvv10:04:07

you could then check data for what you want and rethrow if not the exception.

Jim Newton10:04:12

@kelvended, How do I find the code for thrown? ? When I press M-. in emacs/cider, it cannot find the source code.

kelveden10:04:10

I don't use Emacs myself but even in Cursive I can't step into those for some reason - I tend to just "step into" is instead as the code is all in clojure.test. Anyway here's the code: https://github.com/clojure/clojure/blob/master/src/clj/clojure/test.clj#L504-L535

alexmiller12:04:44

thrown? Is not actually a function

alexmiller12:04:12

It’s actually a special symbol understood by is

kelveden12:04:28

Ah yes of course the 'thrown? is just the dispatch value.

alexmiller13:04:25

you are the 973rd person to be confused about this :)

andy.fingerhut10:04:53

Are you concerned that some other exception other than the one you are testing will occur? Every JVM exception has a class, and there are many such classes. You can give a class name in the catch expression, and such a catch will only catch exceptions with that class, or one of its subclasses.

Jim Newton10:04:33

yes, so which class name should I give for exceptions generated by ex-info ?

gerritjvv10:04:53

clojure.lang.ExceptionInfo <<--

andy.fingerhut10:04:17

You can find out in a REPL by doing a catch on the most general class for all JVM exceptions, Throwable, and then in the exception handler print out the (class x) of the exception x

✔️ 1
gerritjvv10:04:22

(doc ex-info)
-------------------------
clojure.core/ex-info
([msg map] [msg map cause])
  Create an instance of ExceptionInfo, a RuntimeException subclass
   that carries a map of additional data.

✔️ 1
Jim Newton10:04:22

@gerritjvv yes reading your reply as we speak. Thanks for the helpful example.

👍 1
hindol10:04:36

Suddenly clojure -A:new stopped working though I have it defined in ~/.clojure/deps.edn. It instead tries to look for a deps.edn in the current directory. Used to work.

kelveden10:04:35

Have you defined a CLJ_CONFIG environment variable by any chance?

hindol11:04:13

Okay, so this command works under WSL just fine, using the Linux version of tools.cli. Only under Windows there seems to be an issue.

teodorlu11:04:25

Consider posting in #clj-on-windows -- they might be interested 🙂

kelveden11:04:57

Yeah, it looks like support is still in an alpha stage: https://github.com/clojure/tools.deps.alpha/wiki/clj-on-Windows

Jim Newton10:04:10

Lots of functions take a predicate such as remove. I find myself often writing the following ideom.

(remove (fn [x] x=something) my-sequence)
what I'd rather write is
(remove (eql something) my-sequence)
Does such a function eql exist? Of course I can write it in one line, but seems like it ought to already be there.

yuhan10:04:46

it's idiomatic to use sets in this case: (remove #{something} sequence)

💯 1
👍 1
yuhan10:04:05

or you could always use (partial = something) or #(= % something) , no need for a specialized function

Jim Newton11:04:07

ah because a singleton set acts like an equivalence predicate for its singular content. clever

jaihindhreddy11:04:40

Yup, unless the set contains false or nil. Sets when called as fns return the arg if present and nil otherwise, both are falsy in this case and contains? would be more appropriate.

hindol12:04:08

Does clojure.java.shell work under Windows? Can't seem to make it work.

hindol12:04:55

Getting this: CreateProcess error=2, The system cannot find the file specified

teodorlu12:04:02

Got some example code?

teodorlu12:04:57

If I remember correctly, clojure.java.shell runs commands directly, rather than going through bash or cmd. I've had to use absolute paths to get around the issue.

sogaiu12:04:11

...and then use clojure.java.shell with the resulting path

teodorlu12:04:24

Nice ☝️

sogaiu12:04:43

the good parts come from: @U3DAE8HMG 🙂

👌 1
lambdalove 1
hindol12:04:50

@U3X7174KS I was simply trying (shell/sh "dir").

hindol12:04:26

@UG1C3AD5Z That function is cool!

🙂 1
teodorlu13:04:44

I think I'd look into a full path as suggested above, then. I don't have a Windows system at hand, so testing is a little hard. Is dir a shell builtin or a program? where dir might help you discover that.

teodorlu13:04:30

Another option is starting a shell to run a command. Something similar to cmd /c dir, if I recall correctly. See https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/cmd

teodorlu13:04:37

;; On my Linux system, this works:
(sh "bash" "-c" "pwd")
;; => {:exit 0, :out "/home/teodorlu/.../scratchproject\n", :err ""}

;; For the record, this also works, since pwd is "normal" program:
(sh "pwd")
;; => {:exit 0, :out "/home/teodorlu/.../scratchproject\n", :err ""}

(sh "cmd" "/c" "dir")
;; Might give you what you want?

hindol13:04:48

As a workaround, I ran the same thing from Windows Subsystem for Linux and ls etc. worked. dir is a Windows inbuilt command, same as ls. Lists the contents of the current dir.

hindol13:04:47

where is not available on Windows. I have a workaround, so not looking into this any more immediately. Thanks for the help.

sogaiu13:04:31

i've had where work for me in my windows 10 environments -- unlike which i think one can get multiple results

hindol13:04:21

Oh, I was thinking about which. where seems to work, but no result for where dir.

sogaiu13:04:49

right, as you said before dir is a built-in. i presume that's why it doesn't show up.

☝️ 1
OrdoFlammae13:04:51

Once I've written a clojure program, are there any ways to decrease the startup time? It seems rather large. Can I compile to binary or something?

kelveden13:04:58

The cry of every JVM engineer in history... The short answer is: most of the startup time you're seeing is likely to be the JVM itself starting. There are numerous posts on tuning that startup time. As for compiling to binary - there is https://www.graalvm.org/docs/reference-manual/native-image/ but I've found it a difficult beast to wrestle with so far. There's also the possibility that the code itself is trying to do something at startup - so you should minimise that. This is part of the reason that writing command line apps is one of the few times I don't reach for Clojure.

sogaiu13:04:19

depending on the details, babaska night be worth considering

1
Jim Newton13:04:38

Is there a cousin of map which does not accumulate return values? for example simply returns the sequence it iterated over?

dpsutton13:04:32

in an immutable language that's kinda built in. (do (map f coll) coll)

manutter5113:04:35

oh wait you want to return the original seq

dpsutton13:04:00

but most likely you want (do (doseq ...) coll) since its for side effects

☝️ 1
noisesmith13:04:47

or run! which works exactly like two-arg map but returns nil

dpsutton13:04:08

i always forget aobut that one. thanks

teodorlu13:04:20

We might be interpreting the question differently. Map returns a lazy sequence. Whether you realize it all, is up to you.

(take 5 (map (partial * 10) (range)))
  ;; => (0 10 20 30 40)

Jim Newton14:04:58

Actually I don't care what the return value is, I just want to call something like map and not accumulate the return values.

(doseq [x items]
   (do-something-with x))
in Common Lisp there is a function mapc which is like the clojure map but it simply returns its 2nd argument without accumulating anything, and calls the given function iteratively on each element of items presumably for side effect. Thus it returns false if it didn't iterate over anything, and returns true if it did. something like the following (mapc println items) which turns items But i'm happy with doseq, it does what I need.

noisesmith14:04:51

@jimka.issy this is what run! is for

noisesmith14:04:09

user=> (run! println [:a :b :c])
:a
:b
:c
nil

✔️ 1
Jim Newton14:04:00

Can someone please help me understand this error message?

clojure-rte.core> (let [a '((1 2 3) (2 1 3) (1 3 2) (3 1 2) (2 3 1) (3 2 1))
                        b  #{(1 2 3)
                             (1 3 2)
                             (2 1 3)
                             (2 3 1)
                             (3 1 2)
                             (3 2 1)}]
                    (= (set a) b))
Execution error (ClassCastException) at clojure-rte.core/eval20206 (form-init4386036104585295471.clj:15176).
class java.lang.Long cannot be cast to class clojure.lang.IFn (java.lang.Long is in module java.base of loader 'bootstrap'; clojure.lang.IFn is in unnamed module of loader 'app')
clojure-rte.core> 

noisesmith14:04:08

IFn is the interface for things you can call

noisesmith14:04:18

(f) in clojure means "call f"

noisesmith14:04:25

(1) means "call 1"

noisesmith14:04:31

1 isn't an IFn, you can't call it

Jim Newton14:04:42

Oh, is #{(1 2 3)} trying to call the function 1 ? I just need to quote the items.

noisesmith14:04:59

or use [] instead of () to get a sequential collection

noisesmith14:04:24

you can quote the entirety '#{(1 2 3) ...}

noisesmith14:04:50

or use vectors #{[1 2 3] ...}

noisesmith14:04:53

both would work here

Jim Newton14:04:03

so [] interprets its contents as literals, and #{} evaluates them.

noisesmith14:04:21

[] builds a collection and takes no further action

noisesmith14:04:31

() builds a collection then executes

noisesmith14:04:40

' prevents the execution step if any, and also prevents resolving symbols to their current value

noisesmith14:04:45

this might help see some of the differences:

ins)user=> (def a 1)
#'user/a
(ins)user=> (= [a] '(1))
true
(ins)user=> '(a)
(a)
(ins)user=> [a]
[1]

Santiago15:04:48

I’m having trouble identifying the source of a bug. Isn’t there a way to pause execution at specific points and evaluate what’s going on in that environment? e.g. in the R language you can use the browser() function to stop evaluation and give you back control at thatpoint

noisesmith15:04:47

there are "debug repl" implementations that allow that, but in practice since our data types are immutable, it suffices to capture data in scope (a simple def inside your function can do that while debugging)

noisesmith15:04:16

or the new tap> facility

hindol15:04:26

CIDER has a nice debugger if you are using Emacs.

kelveden15:04:33

I use Cursive and so do have the ability to set breakpoints but I actually find myself using https://github.com/dgrnbrg/spyscope more.

Santiago15:04:01

nice thanks everyone I’ll check those points

Jim Newton16:04:38

Is there a cousin of let which lets the n'th binding rever to bindings 0 through n-1 ?

Jim Newton16:04:52

In Common Lisp it is called let*

Jim Newton16:04:03

in scheme it is called letseq

OrdoFlammae16:04:43

I think normal let gives you that ability.

👍 1
Jim Newton16:04:19

equivalent of:

(let [a 1]
  (let [b (+ 1 a)]
    (let [c (+ a b)] ...
?

Michael Stokley16:04:09

user=> (let [x 5 y (inc x)] y)
6

alexmiller16:04:48

Yes, this is just normal let in Clojure

👍 1
Jim Newton16:04:39

Are you sure? experiments show otherwise.

clojure-rte.core> (let [a 100]
                    (let [a a]
                      a))
100
clojure-rte.core> 

Jim Newton16:04:34

ahhh I see, each expression on the right hand side can use any variable above on the left hand side. yes it seems you're right.

Jim Newton16:04:17

So we cant swap a and b with

(let [a b
      b a] ...)
like in Common Lisp

manutter5116:04:12

True, but you can do (let [[a b] [b a]])

manutter5116:04:53

Yeah

(let [a 1 b 2
      [a b] [b a]]
  [a b])
=> [2 1]

Jim Newton16:04:04

And apprently I can bind the same value multiple times. That's cool!

(let [a (f)
      a (remove-duplicates a)
      a (sort a)]
  ...)

lispyclouds16:04:00

if its a series of transforms youre doing using one of the threading macros may be useful: (-> (f) remove-duplicates sort) https://clojure.org/guides/threading_macros

Mitch16:04:01

is lein install the preferred way to get local dependencies into your classpath in a lein project?

noisesmith16:04:11

it is the lowest complexity, but it's still inconvenient (eg. requires restarting a repl to see changes in the lib)

noisesmith16:04:55

with deps.edn you can use :local/root to declare a file-system dep, there are plugins for lein that attempt to do similar (but less convenient in my experience)

Mitch16:04:15

cool, thank you very much. I think it is high time for me to seriously consider making the switch

Jim Newton16:04:36

just a pedagogical example. the general case might be more than just a series of transforms of course

Jim Newton16:04:58

If I have a sequence of objects, and from each object I can extract a key and a value, how can I best build the hashmap from that?

Jim Newton16:04:58

If I have a sequence of objects, and from each object I can extract a key and a value, how can I best build the hashmap from that?

noisesmith16:04:26

this sounds like a job for reduce:

(reduce (fn [m o] (assoc m (get-key o) (get-val o)))
        {}
        object-list)

1
noisesmith16:04:34

actually, seeing your example, map suffices - I thought you wanted all the keys in one map

noisesmith16:04:53

user=> (map (fn [[idx kvs]] (into {} (map (fn [[_ k v]] [k v])) kvs)) input)
(#:clojure-rte.core{:Fox 1, :Cat 1} {:sigma 3} #:clojure-rte.core{:Wolf 4} #:clojure-rte.core{:Lion 2} {})
*edit: swap out map for mapv if vector is a strict requirement

Jim Newton16:04:10

clojure-rte.core> (rte-to-dfa '(:cat (:or ::Cat ::Fox) :sigma ::Lion ::Wolf))
([0 [[0 :clojure-rte.core/Fox 1] [0 :clojure-rte.core/Cat 1]]]
 [1 [[1 :sigma 3]]]
 [2 [[2 :clojure-rte.core/Wolf 4]]]
 [3 [[3 :clojure-rte.core/Lion 2]]]
 [4 nil])
clojure-rte.core> 
I'd like t to convert this to an array of hashmaps
[ { :clojure-rte.core/Fox 1
                      :clojure-rte.core/Cat 1}
                   {:sigma 3}
                   {:clojure-rte.core/Wolf 4}
                   {:clojure-rte.core/Lion 2}
                   {}]

Jim Newton16:04:22

This represents a finite-automaton. where arr[n] is a map of transitions, the key is the transition label, and the value is another index in the array.

Jim Newton16:04:52

including arr[4] = {} as there are no transitions from state 4

SoV417:04:50

@jimka.issy hmm interesting puzzle, what is rte-to-dfa (..something something finite automata?) and is this the ideal place to do this conversion... if so i can think of a few hacky ways to get that output from that input, but nothing especially elegant comes to mind... maybe someone has better ideas on changing a sequence of vectors into a hash map reliably while dropping a bunch of index vals

noisesmith17:04:30

I have a working solution in a single call to map in the thread above

Jim Newton18:04:29

I came up with a solution.

Jim Newton18:04:41

what is rte? it stands for rational-type-expression. You can read something about it in this blog posthttps://blog.ambrosebs.com/2020/03/30/what-type-clojure.html

Jim Newton18:04:30

It is a mathematically rigorous approach to spec. I'm converting my phd thesis from Common Lisp to clojure. I don't want to promise too much but it is an interesting project for me to learn clojure.

SoV413:04:42

nice. best of luck with your projects! it's interesting what it will look like now, and then what you would make it look like with clojure experience after a few seasons.

David Pham18:04:15

People asserts that a Clojure codebase has more parenthesis than those in other languages, is it true though? I think it could be true for the density of parens, but I believe that we have fewer lines and parens in absolute number for the same number of feature than other languages?

rymndhng18:04:51

That is a reasonable way of putting it. I have the same thought.

noisesmith18:04:36

paren count should be quite comparable as well - f() becomes (f) - the paren count for most things remains the same

David Pham18:04:44

In python, you can access properties and create mathematics without parens.

David Pham18:04:54

So maybe there they win.

seancorfield18:04:20

@neo2551 We probably have more ( ) in arithmetic expressions but fewer overall than C-family languages.

seancorfield18:04:46

(and, yes, the productivity factor can mean a substantial reduction in lines and therefore "punctuation" too)

alexmiller18:04:33

Alan Malloy would be my best guess as to who might be able to address that (I don't think he's on here). Repo is at https://github.com/4clojure/4clojure - 4clojure has not really been updated in many years

noisesmith18:04:26

I'll relay the message

noisesmith18:04:12

he's intentionally avoided changing the clojure version on the site (as that makes comparison to existing solutions unfair or might even break a few older solutions)

David Pham18:04:21

Thanks a lot for your answer! @seancorfield

Michael Stokley18:04:28

suppose my data structure is a two dimensional vector. is there a more idiomatic approach to getting values from that matrix than (nth (nth...))? i'm seeing clojure style guides advise against index based collection access.

David Pham18:04:12

What about get-in?

noisesmith18:04:54

get-in works with vectors, as long as you know you won't have seqs mixed in

David Omar18:04:05

Hey! I while ago someone shared a website that, given the inputs of the function, returned the functions that could be called. It was specific for Clojure, and it was pretty nice because you could find functions you didn't know existed. I'm trying to look for it on Google, but I can't. Does someone have it?

noisesmith19:04:18

IIRC it was a library from Raynes that did this - it's actually not so hard to build from scratch

MatthewLisp20:04:47

Hello expertes, i'm trying to do some basic java interop but it's not working, what i'm doing wrong here?

(import  java.security.SecureRandom
         java.math.BigInteger)

user> (.probablePrime java.math.BigInteger 1024 (SecureRandom.))
Execution error (IllegalArgumentException) at user/eval14128 (form-init5284286588528896621.clj:155).
No matching method probablePrime found taking 2 args for class java.lang.Class

markmarkmark20:04:23

Should be (BigInteger/probablePrime 1024 (SecureRandom.))

markmarkmark20:04:53

since probablePrime is a static method of the class, it's accessed like Class/staticMethod

MatthewLisp20:04:55

ohh now i get it, thanks 🙂

MatthewLisp20:04:34

does static means that i don't have to instantiate it?

markmarkmark20:04:53

Yeah, static means that it belongs to the class rather than an instance of a class

markmarkmark20:04:06

for instance, Math/sqrt

MatthewLisp20:04:10

apparently i'm not casting the method on the right class