Fork me on GitHub
#beginners
<
2017-12-06
>
aconanlai00:12:26

hey i've got a dumb question...

aconanlai00:12:08

when i run lein figwheel, the resulting REPL that i have access to - how do i navigate in it? i can't use arrow keys to navigate within the block i'm typing, or pressing up arrow doesn't reveal last command, etc

eggsyntax02:12:12

@aconanlai calling it as rlwrap lein figwheel will give you typical readline stuff like up-arrow for history. Stuff like navigating between lines depends on the environment. For stuff like that, I'd recommend starting figwheel from inside an editor/IDE instead of from a terminal.

eggsyntax02:12:40

(you many need to install rlwrap if you don't already have it -- see https://github.com/hanslub42/rlwrap )

aconanlai16:12:44

+thank you! 🙂

hawari07:12:25

Hi everyone, is fdef in spec doesn't actually validate the input and output of the function when the function is called?

shidima09:12:54

I'm having some problem with my code, and if I run it in cider-debug I can see what the problem is, but I dont understand why.

leonoel09:12:11

arguments to recur seem to be in the wrong order

leonoel09:12:26

additionally, the atom is not needed

leonoel09:12:01

(loop [sheet spreadsheet
          checksum 0]
         (if (empty? sheet) checksum
             (recur (rest sheet) (+ checksum (calculate-list (first sheet)))))

shidima09:12:03

Ah, would it also work if I change the order of the arguments in the loop vector?

shidima09:12:54

it is indeed working now. So the order of the loop and the recur need to be the same.

New To Clojure10:12:01

Hi guys, how to avoid nesting during error checking?

(defn foo [x y z]
  (if (< x 0)
    (throw (IllegalArgumentException. "Positive x is required"))
    (if (> y 0)
      (throw (IllegalArgumentException. "Negative y is required"))
      (if (= y -100)
        (throw (IllegalArgumentException. "Y -100 is prohibited."))
        (if (or (< z 0) (> z 100))
          (throw (IllegalArgumentException. "Z in (range 101) is required"))
          (* x y z))))))

lispyclouds10:12:52

@ghsgd2 If only checking the args, I use pre conditions like this:

(defn foo
  [x y z]
  {:pre [(< x 0) (> y 0) (= y -100) (or (< z 0) (> z 100))]}
  (* x y z))

New To Clojure11:12:54

Is it a good coding style to count :bar the following way (is that optimized by compiler)?

(count (filter #(= % :bar) [:foo :bar :bar :foo :foobar]))

tony13:12:39

@ghsgd2 (:bar (frequencies [:foo :bar :bar :foo :foobar]))

sam14:12:01

@ghsgd2 if you want to keep your messages for the exceptions and also avoid nesting, I’d recommend the cond function:

user=> (defn foo[x y z]
  #_=>   (cond
  #_=>     (< x 0) (throw (IllegalArgumentException. "Positive x is required"))
  #_=>     (> y 0) (throw (IllegalArgumentException. "Negative y is required"))
  			...
  #_=>     :else (* x y z)))
#'user/foo
user=> (foo -1 2 3)

IllegalArgumentException Positive x is required  user$foo.invokeStatic (:3)

sam14:12:05

Correction: cond is a macro, not a function 🙂

New To Clojure14:12:28

@tonywang897 >`(:bar (frequencies [:foo :bar :bar :foo :foobar]))` but it will be doing unneeded work computing frequencies of :foo and :foobar @sammy.castaneda90 that's an option, thank you!

rauh15:12:50

@ghsgd2 1. Exceptions stop evaluations of the function, so no need for an else. You can just do (when x (throw...)) (all good to go) 2. (count (filter ...)) won't be optimized by the compiler. It'll generate the sequence lazily. If you need performance you'd have to reduce this yourself or use transducers.

New To Clojure15:12:23

@rauh 1. So it will be (do (when x (throw...)) (when y (throw...)) (all good to go)). 2. I. e. reduce or transducers. I see. Thank you a lot!

diginomad16:12:18

a very basic question

diginomad16:12:45

Why does (realized? (lazy-seq [1 2 3])) return false

diginomad16:12:23

What does this lazy sequence have to "realize "?

diginomad16:12:57

i see the above code in LazySeq.java

markmarkmark16:12:07

@diginomad none of the lazy sequence has been realized because it hasn’t been used. It’s lazy in the sense that it won’t do anything with the [1 2 3] at all until you actually use it by passing it as an argument to a function like seq

diginomad16:12:28

What is the fn when i say (lazy-seq [1 2 3])

diginomad16:12:43

return new PersistentList()?

markmarkmark16:12:04

lazy-seq is a macro that wraps the body into a fn. in that case the fn is (fn [] [1 2 3])

markmarkmark16:12:00

you can see it if you type (macroexpand ’(lazy-seq [1 2 3])) into your repl

diginomad16:12:09

so,(class (lazy-seq [1 2 3])) returns Fn?

markmarkmark16:12:51

no, it returns a clojure.lang.LazySeq object

diginomad16:12:52

i am having trouble getting the concept of realization i guess

diginomad16:12:03

i was of the opinion that (lazy-seq [1 2 3]) is already realized

markmarkmark16:12:06

if you’re using a repl it makes things like lazy seqs a little harder to understand because the repl will automatically realize the sequence to print it to the screen.

diginomad16:12:19

that is one other thing

diginomad16:12:51

but i guess it makes sense

diginomad16:12:00

if we have a very very huge list

diginomad16:12:12

and we want to make it Lazy from thereon

markmarkmark16:12:24

I think a quick rule of thumb is that if you’ve never used the lazy seq anywhere besides where you’re binding it, then it hasn’t been realized.

diginomad16:12:25

we can wrap that into LazySeq

diginomad16:12:41

and use it without fear of OOMException from thereon

diginomad16:12:21

until actually "used"

markmarkmark16:12:02

well, if the list already exists in memory somewhere, then wrapping it into a lazy sequence doesn’t really do a whole lot. in the lazy-seq case, if you’re wrapping a vector in a lazy-seq then that vector is completely held in memory.

diginomad16:12:29

thats why i said from thereon

diginomad16:12:04

what if i am planning to put a million more

diginomad16:12:19

not sure if what i am saying is technically correct though

markmarkmark16:12:44

it really depends on where you’re getting the list from. For instance, if you’re reading it from a file, then it’s definitely possible to read it from the file as a lazy sequence.

manutter5116:12:37

The main thing to remember about lazy seqs is that if you expect (prn foo) to give you [1 2 3] and instead it gives you [email protected], you need to put a doall around foo to realize it into the actual values you’re expecting.

manutter5116:12:06

And of course to make sure the value of foo won’t go bOOM.

New To Clojure17:12:07

How could it be realized if it's printed as [email protected]?

> (realized? (doall (map #(inc %) [1 2 3])))
true
> (str (doall (map #(inc %) [1 2 3])))
"[email protected]"

manutter5117:12:45

Wow, that surprises me

manutter5117:12:18

seq works

(str (seq (map #(inc %) [1 2 3])))
=> "(2 3 4)"

manutter5117:12:49

but I would have expected doall to return a realized value.

New To Clojure17:12:05

@manutter51 I expected too. Thank you!

alexmiller17:12:42

pr is for printing as readable data

New To Clojure17:12:47

@alexmiller Curious:

(pr-str (map #(do (println "hello world")(inc %)) [1 2 3]))
"(hello world\nhello world\nhello world\n2 3 4)"
It captures System.out output too.

alexmiller17:12:55

Yes, it will for the -str variant. If realizing your data structure has side effects, then you should realize it first

nbardy21:12:28

Is there a function or idiom for mapping conditionally? e.g.

(map-when odd? #(* % 2) [1 2 3])) -> [2 2 6]

noisesmith21:12:12

I don’t know about idiom per se but there’s #(cond-> % (odd? %) (* 2)) as a function

seancorfield21:12:34

(yeah, that's what I was typing in as the answer!)

seancorfield21:12:50

And that's another case where I'd reach for the predicate-threading variant we have in our "util" library at work: (map #(condp-> % odd? (* 2)) [1 2 3]) 🙂

noisesmith21:12:03

oh nice - I’ve wanted to write condp-> but also wasn’t sure of the name

seancorfield22:12:13

We've had condp-> and condp->> for ages in our code base -- they can be so useful! Another one of our utilities I use a lot is flip (modeled after Haskell) which is like partial except you omit the first argument.

seancorfield22:12:37

At some point I hope we'll open source the namespace that has those things in it...

seancorfield22:12:11

It also has dissoc-all and interleave-all.

noisesmith23:12:33

a coworker named flip qartial since q is flipped p

solf22:12:58

Any reason why core.match isn't included by default on clojure? Is it not "idiomatic"?

admay22:12:07

Rich ins’t a big fan of pattern matching

admay22:12:51

It’s a long video but he mentions it in there somewhere

admay22:12:02

Anything in particular you looking to do with core.match or just curious about leaving it out?

solf22:12:43

Not specially, but I thought pattern matching was the functional way of solving a basic problem I'm having

solf22:12:12

I'm writing a cli that can do different actions, with different parameters, for example action1 arg1 arg2 and action2 arg1 arg2 arg3

solf22:12:59

I thought that match was an easy way to both dispatch each action to it's corresponding function and verify that they had the correct arguments

admay22:12:24

Are you using clojure.tools.cli?

solf22:12:42

Ah, nop. will look into that

seancorfield22:12:34

@dromar56 If you just want to dispatch on a string for the action and handle those cases separately, a multimethod might be a reasonable approach -- if you don't want the full-on argument parsing of tools.cli (which is geared much more to Posix-style command lines).

solf23:12:24

Yes since it's a learning project I think I'll use destructuring and multimethod for now

seancorfield23:12:19

(I maintain tools.cli but I'm perfectly happy to point folks at simpler solutions 🙂 )

solf23:12:18

So I got this:

(defmulti action-dispatch first)

(defmethod action-dispatch "action1" [[action arg1 arg2]]
  (if (and (string? arg1)
           ((every-pred number? pos?) arg2))
    (do-something  action arg1 arg2)
    (print-usage)))

(defmethod action-dispatch "action2" [[action arg1 arg2 arg3]]
  (if (and (string? arg1)
           (string? arg2)
           ((every-pred number? pos?) arg3))
    (do-something-else  action arg1 arg2)
    (print-usage)))

(defmethod action-dispatch :default [_]
  (print-usage))

solf23:12:42

Is that an ok way of doing argument validation?

solf23:12:40

I'm not happy I had to write (print-usage) three times

solf23:12:54

Oh I guess I could remove all calls to print-usage and instead do something like (when-not (action-dispatch args) (print-usage))

noisesmith23:12:00

you could make a dispatch function that either returns ::error or (first arg1) then have a single dispatch to print your usage

noisesmith23:12:12

then do all the validation in the dispatch

noisesmith23:12:28

maybe that’s hacky

seancorfield23:12:54

Command line arguments are all strings so I wouldn't expect number? to return true...

solf23:12:58

It would be a long dispatch function, since it has differents kinds of arguments for each action

solf23:12:18

Ah that's right, will need to cast it somewhere

seancorfield23:12:35

Convert, (Long/parseLong arg2) and catch exceptions. Not cast.

solf23:12:35

Will do, thanks

noisesmith23:12:32

@dromar56 what about two multimethods - one for action-dispatch and antother for validating the action

noisesmith23:12:51

and both could dispatch on the first item in the coll

noisesmith23:12:09

then (if (validate args) (dispatch args) (print-usage))

noisesmith23:12:14

or (defprotocol IAction (validate [this arglist]) (execute [this arglist])) and select some instance of IAction based on the first item in the arglist (?)

solf23:12:26

that seems nice @noisesmith, I will try the defprotocol method since I haven't used it yet

noisesmith23:12:03

then you’d have like (def action1 (reify IAction (validate [this args] (and (string? (first args) …)) (execute [this args] (do-something …))

noisesmith23:12:07

one for each action

admay23:12:23

I’m surprised no one has mentioned spec yet

noisesmith23:12:46

haha sometimes I forget what channel I’m in

admay23:12:49

dependencies intensify

admay23:12:48

I’m just going to leave this here to hopefully get us back on track lol https://www.braveclojure.com/