Fork me on GitHub
#beginners
<
2021-06-26
>
Jeffery Swensen01:06:04

hey all. from http://braveclojure.com exercises, I'm trying to write mapset which works like map but returns a set. I'm struggling with getting it to work for more than one collection argument

(defn mapset
  "map but returns set"
  [func & colls]
  (set (map func colls)))

Jeffery Swensen01:06:57

(mapset inc [1 1 1 2] [2 2 2 3]) gives me > ; class clojure.lang.PersistentVector cannot be cast to class java.lang.Number

indy01:06:17

(defn mapset
   "map but returns set"
   [func & colls]
   (set (apply map func colls)))

indy01:06:30

Also (map inc [1 2] [3 4]) will fail because only a single number can be incremented.

indy01:06:48

So maybe (mapset + [1 1 1 2] [2 2 2 3])

Jeffery Swensen01:06:00

brilliant, thank you!

j20:06:05

I'm taking a windows file path as an argument (i.e. "C:\Program Files") and feeding it to http://java.io/file. I get an error because of special characters in the string. What's the idiomatic way to escape those chars?

borkdude21:06:04

"C:\\Program Files" probably

borkdude21:06:38

but in Java this also works on Windows I think:

C:/Program Files

j22:06:02

Thanks @U04V15CAJ! Is there a function that will escape special characters for me?

andy.fingerhut02:06:52

If you read a string like that from a file or user input, there is no need to escape them.

andy.fingerhut02:06:42

If you have a string typed into your Clojure source code, then it is a lot like a Java or C string, where there are special characters like \n for a newline, so a backslash itself must also be escaped if you want a backslash in the resulting string.

andy.fingerhut02:06:21

I've never heard of anyone writing a bit of code that takes such strings you want to put in your source code, and escape them for you, but it wouldn't be difficult to write one if you really want it.

andy.fingerhut02:06:43

Most such strings in source code are relatively infrequent, and I believe developers typically escape them by hand-editing their programs.

noisesmith16:06:45

right, "\:" is not a valid string, the clojure reader rejects it

Rob Haisfield21:06:49

Can someone help me fix this Spec please? I’m trying to check if something is a valid arousal level, which must be between 0 and 1 (s/def arousal-level? (s/or #(< 0 %) #(> 1 %))) Unexpected error (AssertionError) macroexpanding s/or at (src/anxiety_loop/core.clj:1:166). Assert failed: spec/or expects k1 p1 k2 p2..., where ks are keywords (c/and (even? (count key-pred-forms)) (every? keyword? keys))

dpsutton21:06:29

That’s a really good error message. S/or expects k1 p1 where the k’s are keywords.

vncz21:06:54

Yeah I guess every condition has a keyword to identify it

vncz21:06:27

So you would have (s/or :cond-1 #(< 0 %) :cond-2 #(> 1 %))

Fredrik21:06:38

This is useful eg. when you call s/conform on a value, for it can let you know which condition was satisfied

dpsutton22:06:03

Also once you understand what’s going on, you can remove the need for the s/or with (< 0 % 1)

🙌 6
Rob Haisfield22:06:38

Oh that’s cool I forgot that’s how that works

dpsutton22:06:50

But solve it with the or so you understand what’s going on. And then simplify

Rob Haisfield22:06:36

Good advice. So for some reason this still isn’t working like I expected… I decided to change it to an integer between 0 and 100.

dpsutton22:06:44

Does s/def work on a symbol like that? Specs are usually registered as a keyword in a central registry

Alex Miller (Clojure team)22:06:14

function specs are registered with symbols so this is allowed (but is not what was intended)

Rob Haisfield22:06:36

Good advice. So for some reason this still isn’t working like I expected… I decided to change it to an integer between 0 and 100.

Fredrik22:06:48

s/def can take both keywords and symbols, but they have to be fully namespace qualified. Look at res in clojure.spec.alpha

dgb2322:06:34

here it is a def so just the spec

dgb2322:06:30

the mouth of the crocodile has to look to the other sie @rob370

dpsutton22:06:57

Calling int on the boolean seems strange

Rob Haisfield22:06:17

You’re right. I think what I’m actually trying to do is make sure the argument is an int

Fredrik22:06:50

The value 101 satisfies pos? , so it 'passes' the spec (specs are not best thought of as predicates, though, rather as descriptions of the shape of data). What you want is to use s/and instead of s/or when your value has to satisfies all conditions, ie. both be positive and less than 100. In this case you can get away with using a single function:`(s/def ::arousal-level #(< 0 % 100))`

Alex Miller (Clojure team)22:06:07

specs absolutely are best thought of as predicates describing value sets

Fredrik01:06:26

You're right, I was being crude. I should have said: Having defined a spec, you also get more than something just capable of producing boolean-valued expressions, like ways to generate data of wanted shape and s/conform to "pick apart" and say in what way a value satisfies a spec.

Rob Haisfield22:06:17

You’re right. I think what I’m actually trying to do is make sure the argument is an int

Rob Haisfield22:06:10

(def arousal-level (s/and pos?
                          int?
                          #(> 100 %)))
I think I got it

Fredrik22:06:37

There is actually a function pos-int? in the standard library, I discovered just now.

Rob Haisfield22:06:27

Thank you for the help everyone

🎉 9
dgb2322:06:39

It’s great that you solved your problem but It’s still weird that you use > instead of < !

Fredrik22:06:41

They are checking for an integer less than 100, which (> 100 %) does

👍 6