Fork me on GitHub
#beginners
<
2017-12-07
>
Bert Weidenflunders02:12:57

hey all, I'm still trying to get the cljs version of my factorial function to work for big numbers

Bert Weidenflunders02:12:19

(defn- factorial-helper [n result]
  (if (= n 1)
    result
    (recur (dec n) (* n result))))

(defn factorial [n] 
  (factorial-helper n 1))

Bert Weidenflunders02:12:56

when I try with large numbers it returns "Infinity"

Bert Weidenflunders02:12:26

someone mentioned using a js or cljs library that keeps the exact digits of the number, but I'm having trouble implementing it.

Bert Weidenflunders04:12:55

I tried like this:

(defn- factorial-helper [n result]
  (if (= n 1)
    result
    (recur (e/dec n) (e/* n result))))

(defn factorial [n] 
  (factorial-helper n 1))

Bert Weidenflunders04:12:29

(:require [com.gfredericks.exact :as e]))

Bert Weidenflunders04:12:46

and just calling it like this: (factorial 10000)

lispyclouds05:12:49

@info Im not sure but does writing it like this help?

(def ONE (e/native->integer 1))

(defn- factorial-helper [n result]
  (if (e/= n ONE)
    result
    (recur (e/dec n) (e/* n result))))

(defn factorial [n]
  (factorial-helper n ONE))

(factorial (e/native->integer 10000))

sam08:12:37

Curious about this. At my work we use Java, and DDD is something they are quite religious about. One pattern that I keep seeing is the use of converters. Some new class implements Converter<A,B>, which then implements the function: public B convert(A a) So I wanted to see what this would look like in clojure… I have something like this:

(defn defconverter [map-for-conversion defaultfn]
  (fn [key]
    (if (contains? map-for-conversion key)
        (get map-for-conversion key)
        (defaultfn key))))

(def a-to-b
  (defconverter
    {:a 1
     :b 2
     :c 3}
    (fn [key] (throw (IllegalArgumentException. (str "Could not find " key))))))

(a-to-b :a) => 1
(a-to-b "asd") => IllegalArgumentException Could not find asd
I was wondering what I would have to do to be able to define a converter in the following way:
(defconverter a-to-b
  {:a 1
   :b 2
   :c 3}
  (fn [key] (throw (IllegalArgumentException. (str "Could not find " key)))))
My guess is that I would have to use macros? What would that look like?

sam13:12:09

Figured it out 🙂

(defmacro defconverter [fn-name map-for-conversion defaultfn]
  (list
    'def fn-name (fn [key]
                    (if (contains? map-for-conversion key)
                        (get map-for-conversion key)
                        (eval (list defaultfn key))))))

noisesmith16:12:56

eval inside a macro is usually wrong

sam22:12:35

@noisesmith Before that i tried without the eval and without the list on the last line and it would not work. It was complaining... but this works as expected. Also just saw the case function may be suitable for this scenario as well. Can you explain why eval in macro is usually wrong?

noisesmith22:12:49

it’s spinning up a whole new compilation context in order to compile one line inside another compilation that’s already running

noisesmith22:12:29

and it’s not quoted, so it’s not running the compiler at runtime - which means what you are doing there should be possible without needing eval

sam13:12:02

@noisesmith here’s the output if I drop the eval and list:

(defmacro defconverter [fn-name map-for-conversion defaultfn]
  (list
    'def fn-name (fn [key]
                    (if (contains? map-for-conversion key)
                        (get map-for-conversion key)
                        (defaultfn key)))))

(defconverter a-to-b
  {:a 1
   :b 2
   :c 3}
  (fn [key] (throw (IllegalArgumentException. (str "Could not find " key)))))

(a-to-b :a) => 1
(a-to-b :d) =>
ClassCastException clojure.lang.PersistentList cannot be cast to clojure.lang.IFn  user/defconverter/fn--10571 (form-init8994047963818758313.clj:27)
Any suggestions on how to get it to work without eval?

noisesmith18:12:22

in general, ` makes writing macros much easier

noisesmith18:12:26

anyway, with your current approach, turn (fn ...) to (list 'fn ...) and ensure that only things that the macro is meant to evaluate are unquoted; this gets very tedious and that’s why ` makes things easier

Salis09:12:28

anyone has a clojure project that uses any google api java library?

Salis09:12:09

I want to know how can I integrate them in clojure project, for example this one https://developers.google.com/google-apps/calendar/quickstart/java

Sabbatical201713:12:42

Hi, I have been interested in Clojure for years and have been reading about it on and off but never really wrote any code. (I am an experienced Python programmer though.) Now I am trying my hand at actually writing some Clojure code in the the Halite competition (https://halite.io/) which seems like a fun way to experiment with various aspects of the language. I found that there is plenty of Clojure documentation (books, blog posts, web sites etc) on the basics but it's harder for me to find higher-level information on how to architect things. A specific example I am wondering about is how to write a function that produces the best possible answer to a question within a time limit of 2 seconds (which is what Halite robots need to do). I am assuming that conceptually the answer is to break it into two functions: the first one just produces (without regard to wall clock time elapsed) a sequence of answers which get better and better; and a second function which just watches this sequence for 1.99 seconds then returns the best answer seen so far and terminates the efforts of the first function. However, I am not sure how to put this together in Clojure. Channels? Threads? Agents? How do I implement a timeout? Any hints (even if vague) would be greatly appreciated! (I do feel capable of following up on a thread, it's just hard to find the right starting point.) Thank you very much!

New To Clojure14:12:16

@sabbatical2017 I would start from

(def *values* (atom []))
(def process (future
               (while true
                 (comment generate and add values to *values* collection))))

(deref process 1990 (last @*values*))

manutter5114:12:31

It’s an example of using timeout in the context of core.async channels.

ibcoleman15:12:55

Hi, anyone successfully set up lein-droid? Could not find template droid on the classpath.

ibcoleman15:12:21

sorry, took this to #clojure-android

Sabbatical201715:12:22

Thank you very much, @ghsgd2 and @manutter51!

Melania15:12:04

Good morning. I am struggling understanding the meaning of % in some functions in clojure for instance for swap! function where records is a map and id is a value of the :id, m is one of the key/value that I want to update the defn looks as follow: (defn update [id m] (swap! records #(if (% id) (update-in % [id] merge m)%))) - can someone read this function for me, especially the %. Thanks in advance

donaldball15:12:56

#(...) is an anonymous function literal. Within that form, % stands for the first argument to the function.

manutter5115:12:35

There’s also %2 for the second arg, %3 for the third, etc.

ibcoleman15:12:00

Does anyone know why leiningen seems to be trying to use localhost to hit clojars and the maven repos?

manutter5115:12:14

Though in general if you have more than a couple args you should write out (fn [arg1 arg2 arg3...] ...)

Melania15:12:15

Thanks - so since I don't have %1,, % assumes that I only have one argument? Going further on the small function I have an if statement - that evaluates % with id. What is % evaluate to. Is it something to do with the "records" atom that I am trying to swap!.

Melania15:12:00

I am just trying to read the whole statement like someone that really knows clojure would do. I am kind of new to the syntax and the concepts.

donaldball15:12:50

(defn update [id m] (swap! records #(if (% id) (update-in % [id] merge m)%)))

donaldball16:12:45

So… records must be a var containing atom. This update fn will, if the records atom contains a map with an entry for the given id, merge the entry’s value with the given map m, otherwise it will leave it alone.

donaldball16:12:23

There are some confusing things about this form though. I tend to avoid the anonymous fn literal, well all the time actually, but particularly when the arg appears more than once.

Sabbatical201716:12:30

I remember seeing somewhere that there is a way to get automatic feedback about Clojure source code being idiomatic. For example (generalizing from my experience with Python) it probably is not idiomatic to say "(= foo true)" because you can say "foo" instead (perhaps this is not a good example because of how truthiness works in Clojure, but I can't think of a better one now.) Perhaps this checking of being idiomatic also has to do with spec somehow, I don't remember. So I vaguely recall that there is a script that looks at your source code and spits out diagnostics on how you could make it more idiomatic. Unfortunately, I was not able to Google my way to this, can anyone give a hint? Thank you!

wilcov16:12:47

Suppose i have a sequence of integers that i want to filter by a relation of each other. I.e. only keep members that are equals to the next one. What would be the idiomatic way to code this? A loop-recur would be easiest for me at the moment but perhaps keep-index/filter/reduce is better?

Sabbatical201716:12:08

Thank you very much, @tbaldridge and @ghsgd2!

manutter5116:12:31

(partition-by identity [1 2 3 3 4])
=> ((1) (2) (3 3) (4))

manutter5116:12:43

that one’s fun too

manutter5116:12:31

(filter #(<= 2 (count %))
        (partition-by identity [1 2 2 3 4 4 4 5 6]))
=> ((2 2) (4 4 4))

Prakash17:12:48

also, with take-nth, so (= (take-nth 2 seq) (take-nth 2 (rest seq)))

Prakash17:12:11

oh u want the items as well, so filter would be the way

wilcov17:12:21

Thanks @pcbalodi @manutter51 i feel like i should be able to solve the issue now =)

Melania17:12:14

Thanks Donald. I don't like the syntax, but I can convert it now to one that I can understand better. Thanks for taking time.

New To Clojure17:12:31

How to handle sequential updates of variables when each pair of values depends on previous pair differently? For example, could write

(let [x0 (...) y0 (...)]
    (let [(x1 (/ y0 (...)) y1 (* x0 (...))]
        (str x1 y1)))
or make each let [x y] a separate function or
(->> [a b]
    ((fn [[x y]] [(...) (...)])) 
    ((fn [[x y]] [(...) (...)])))
What's the best option?

noisesmith17:12:22

let allows back references, you don’t need nested let

noisesmith17:12:10

(let [x0 … y0 … x1 (/ y0 …) y1 (* x0 …)] (str x1 y1))

New To Clojure17:12:01

what if I don't need x0 and y0 after x1 and y1 are calculated? could I delete those bindings (variables) ?

New To Clojure17:12:13

to avoid their usage in let body

noisesmith17:12:16

no, clojure is smart enough to know they are out of scope

noisesmith17:12:38

it’s called “locals clearing” - in fact you need to turn it off explicitly to use debuggers

noisesmith17:12:53

otherwise you try to refer to a value and find it no longer exists

noisesmith17:12:57

(in the debugger)

New To Clojure17:12:59

i. e.

(let [x0 () y0 () x1 () y1 ()] 
 (comment body))

New To Clojure17:12:07

body can see x0 and y0

noisesmith17:12:16

yes - but clojure knows whether it uses them

noisesmith17:12:24

because we don’t have implicit scope

noisesmith17:12:31

so either those symbols are in body or they aren’t

noisesmith17:12:45

the compiler is good at clearing those locals

New To Clojure18:12:39

@noisesmith I mean that if I accidentally used x0 instead of x1 in let body there will be no compiler error about that

noisesmith18:12:02

sure, nested let doesn’t help with that

noisesmith18:12:17

it would have identical behavior

noisesmith18:12:24

perhaps you want to rebind the same name?

New To Clojure18:12:57

@noisesmith I my case, each pair of values depends on previous pair i. e. [x0 y0] [x1(x0, y1) y1(x0 y1)] so I can't rebind x to x and lose previous value before calculating y.

New To Clojure18:12:08

But let is good enough for my purposes

New To Clojure18:12:23

Thanks, @noisesmith, for taking your time

shaun-mahood18:12:14

I'm trying to understand ring-middleware better. When I write a wrap-something middleware, my understanding is that it fires once for the request, then again for the response. Is there a way to set things up so that it only does something on request or response and not the other? Or to deal with them differently?

noisesmith18:12:20

it’s just a higher order function - it’s up to the author whether you do anything before or after the original

noisesmith18:12:59

eg (defn wrap-foo [handler] (fn [request] (f (handler (g request)))) - either f or g could be identity

noisesmith18:12:36

if g is identity, you only change the return value of the handler, if f is identity you only change the input, if both are identity you have the identity middleware

noisesmith18:12:04

and it doesn’t fire more than once - there’s two places it can touch the data

shaun-mahood19:12:06

@noisesmith: Thanks, that helps quite a bit!

mikelis20:12:53

@ghsgd2 you can rebind on the same names, since each line is evaluated at a time

(let [[x y] [1 2]
      [x y] [(+ x y) (- y x)]
      [x y] [(+ x y) (- y x)]]
  [x y])
=> [4 -2]

mikelis20:12:21

what i mean is — the right hand side gets evaluated first and then both rebinds happen at the same time

mikelis20:12:06

this also allows you to eg swap bindings

(let [[x y] [1 2]
      [x y] [y x]]
  [x y])
=> [2 1]

New To Clojure20:12:32

That's exactly what I was searching for. Thank you very much, @mikelis.vindavs!

Sabbatical201721:12:27

I am trying to call a function while rebinding stdout to /dev/null. I was hoping that something like (binding [*out* (output-stream "/dev/null")] ...) would do the trick, but this fails with java.io.BufferedOutputStream cannot be cast to java.io.Writer. Is there a standard or idiomatic way to discard *out*?

Sabbatical201721:12:00

[The context to the question above is that I am trying to start a nightlight server in my app, but the standard nightlight.core/start will do a println to let me know that the server is up. However, that output showing up in the stdout screws up the other command that is consuming the stdout of my clojure app.]

noisesmith21:12:47

the error is telling you it needs a writer

New To Clojure21:12:48

@sabbatical2017 That's not an exact answer but you could use with-out-str and ignore it's return value

noisesmith21:12:51

user=> (io/writer (io/output-stream "/dev/null"))
#object[java.io.BufferedWriter 0x1c3c1eeb "[email protected]"]
user=> (binding [*out* *1] (println "OK"))
nil

noisesmith21:12:13

all you need is to make a writer from the output-stream and it works

noisesmith21:12:26

oh you can use io/writer directly on the file name, no need to create output-stream explicitly

Sabbatical201721:12:37

@noisesmith, sorry for such a newbie question, but how do I avoid No such var: io/writer? I have to know what io is and mention it in my ns macro at the top of the file, right?

noisesmith21:12:18

oh - I used (ns … (:require [ :as io]) ) - I figured you’d know how to find it since you found output-stream which is in the same ns

Sabbatical201721:12:53

Thank you very much, @ghsgd2, @noisesmith, @admay! This is now working for me

noisesmith21:12:22

it’s also possible without using “/dev/null” by creating a proxy of Writer

user=> (binding [*out* (proxy [java.io.Writer] [] (append [c]) (flush []) (close []) (write [c]))] (println "OK") (println "yeah"))
nil

noisesmith21:12:46

all it needs to do is let something call a method and return nil