Fork me on GitHub
#beginners
<
2016-05-11
>
hoopes00:05:13

if i have a set of things i'm running down, are nested when-let forms ok?

(when-let [a (something-could-be-nil)]
  (when-let [b (other-could-be-nil a)]
    (when-let [c (third-could-be-nil b)]
        c)))

donaldball00:05:23

You might prefer the look of (some-> (something-could-be-nil) other-could-be-nil third-could-be-nil))

donaldball00:05:52

avoids the need to name the intermediate results

urbanslug09:05:01

Hey, I am trying to define a local function in a let but issue is the function keeps running when the let is evaluated instead of when the function in the let is evaluated. What can I do about this? I just wish to bind this function and call it later in the function and have it only run when called.

plexus09:05:15

@urbanslug: how does your code look?

urbanslug09:05:33

(defn bro-life []
  (let [print-msg (println “cat”)]
     (println “Will run but print-msg will not")
     (print-msg)))

urbanslug09:05:39

something like that

urbanslug09:05:33

output will be:

cat
will run but print-msg will not

urbanslug09:05:39

The it seems to block

plexus09:05:19

the problem is that (println "cat") is a function call to println instead of being an anonymous function

plexus09:05:55

the easiest is to use the shorthand syntax for anonymous functions, just put a # in front

plexus09:05:22

or you can use fn, or letfn, which is exactly built for this purpose

plexus09:05:44

in your original code what happens is that (println "cat") gets evaluated, and println returns nil, so now print-msg is equal to nil

plexus09:05:39

so then calling (print-msg) is the same as calling (nil), which will give you a NullPointerException

urbanslug09:05:15

My code is much more complex I hope all works simple_smile

urbanslug09:05:46

because I did try wrapping it in a lambda

plexus09:05:52

good luck! simple_smile

plexus09:05:26

maybe it's easier if you pull it into its own defn?

urbanslug10:05:33

Yeah nested #() are not allowed but of course (fn [] …) works because no ambiguity

jswart15:05:36

You have a facts nested within another facts, can you do that?

st15:05:03

one sec.

st16:05:08

I don’t know the exact reason, but when you give a function f to map to a coll, refrain from using the anonymous shortcut.

st16:05:14

So: * use (fn [i] {:date … instead * the get-ins are un-necessary, you can use (:period x) instead

st16:05:43

(defn map-invoices [invoices]
  (map (fn[i] { :date (:period-end i)
                :amount (str "$" (:subtotal i))
                :status (if (:paid i) "Paid" "Unpaid")}) invoices))
=> xxx/map-invoices
(map-invoices [{:period-end "pe" :amount 123 :paid true}])
=> ({:date "pe", :amount "$", :status "Paid”})

jswart16:05:27

I believe the basis for you issue is something like this:

jswart16:05:37

boot.user=> (macroexpand-1 '#({:foo 1}))
(fn* [] ({:foo 1}))

jswart16:05:17

boot.user=> (macroexpand-1 '#(hashmap :foo 1))
(fn* [] (hashmap :foo 1))

jswart16:05:50

as st said by using the #(…) reader literal you putting your hashmap in the function call position b/c hashmaps can use IFn to be used like functions

jswart16:05:09

so you make a thunk, that when called wants to use the hashmap as a function

jswart16:05:23

but you didn’t give it a way to ever receive a value as a key

st16:05:16

@jswart: thanks for explanation. I stumbled upon this issue many times.

jswart16:05:42

yeah when you use #(…) and you want to return data you have to use the non reader literal so ((fn [x] [x 1 2 3]) 7) => [7 1 2 3] becomes (#(vector % 1 2 3) 7) => [7 1 2 3]

jswart16:05:33

tricky. I tend to avoid the #(…) execpt for very tiny functions

jswart16:05:17

I would have made the data munging form and then used partial to make map-invoices like (def map-invoices (partial map transform-fn))

st16:05:23

yes, extracting fn inside map to something named is better.

edreed19:05:49

I working through Clojure Koans and I'm stuck at:

edreed20:05:16

I know that I want to do something with (last coll) (pop coll) `

edreed20:05:31

but I feel like I'm missing something..

edreed20:05:49

Any hints would be super helpful

jswart20:05:54

What you pasted in is the code that handles when the recursive calls should terminate, it feels a bit odd though. Because if you have a collection w/ a count > 1 how will you know to stop?

jswart20:05:58

in general recursive solutions are “divide and conquer”. Where the solution to a problem usually follows the formula If SOME_CONDITION stop else the solution is SOMETHING and a recursive call

jswart20:05:42

Each recursive call does a little bit more of the work, and when you reach the termination clause you start combining the operations on the stack until you get a value.

jswart20:05:46

for example

jswart20:05:49

(defn my-add-coll [coll]
  (if (empty? coll)
    0
    (+ (first coll) (my-add-coll (rest coll))))) 

jswart20:05:57

boot.user=> (my-add-coll [1 2 3])
6

edreed20:05:08

That was a pretty good hint

edreed20:05:23

I'm revisiting it now

jswart20:05:42

One HUGE caveat is that once you have an intuitive understanding of recursion, and how to write something recursive in clojure you should read up on loop, recur and reduce those are special forms / functions.

jswart20:05:04

There is a “gotcha” to recursion on the JVM when you start writing production code, but for now you are probably okay.

edreed20:05:01

taking note of your suggestions

jswart20:05:51

Everything I know about recursion I learned from SICP, a truly amazing book.

jswart20:05:18

that helps build intuition for recursion

jswart20:05:25

good luck on learning clojure!

edreed20:05:56

I'm gonna pickup SICP in the next month or two

jswart20:05:29

its free online as well, as are the videos

jswart20:05:42

i never actually had the book either

jswart20:05:56

We have a work copy and it is great to leaf through

edreed20:05:20

pickup as in sit down and read it

jswart20:05:37

ah cool, yes. it takes time.

jswart20:05:02

I tried to learn clojure and failed b/c I had no functional/CS experience. I did SICP over about 6 months and then came back to clojure.

jonschoning20:05:09

is ^long metadata? what is that useful for?

jswart20:05:51

its a type hint

jswart20:05:58

it prevents runtime reflection

jswart20:05:12

b/c now the compiler knows that state is a long