Fork me on GitHub
#beginners
<
2018-03-01
>
pooboy02:03:13

What are first class functions in clojure?

greglook02:03:49

values which implement clojure.lang.IFn?

greglook02:03:09

more generally, the idea that you can think of functions as values at all, which is a hallmark of “functional” languages

greglook02:03:50

e.g. (let [double (fn [x] (* x 2))] (prn double) (double 4))

greglook02:03:15

is both treating double as a value (because I can call prn on it) and a function (because I can call it on 4)

noisesmith02:03:19

@suryapjr for example, in java the method foo when you call Bar.foo() is not first class - you can't do anything with .foo itself, you can't pass it to another method or store it for later

noisesmith02:03:46

(there are reified reflective objects that "represent" a method but that's a whole other thing and not what people are typically using)

noisesmith02:03:13

a clojure function is an object, so you can pass it as an argument, store it, return it, etc. etc. etc.

matan02:03:24

Any tips on exposing your Clojure code to be run from a python program? 🙂

greglook02:03:25

As far as I know, your options are largely either running a socket that your python code can call, or hosting a python interpreter like Jython in the JVM and using interop.

pooboy02:03:09

My clojure project structure : /name/src/core.clj

pooboy02:03:24

How do i run core.clj via clojure REPL

pooboy02:03:37

not leiningen , only clojure REPL?

noisesmith02:03:12

@suryapjr inside the running repl you can run (load-file "/home/src/core.clj")

noisesmith02:03:46

if you need to require other files you'll also need to set the proper classpath on jvm startup

pooboy02:03:28

@noisesmith cool..how do i run the main function

noisesmith02:03:43

once you have loaded the file into the repl you can run it by the full namespaced name - or if you don't have an ns form in the file, just run it directly because it was defined in your current ns

pooboy02:03:05

I have defined ns

pooboy02:03:27

I want to run it from the REPL

noisesmith02:03:36

OK - so call it by the full name, if it's called main and is in foo.bar ns, call (foo.bar/main)

pooboy02:03:23

CompilerException java.lang.RuntimeException: No such var: name/main, compiling:(NO_SOURCE_PATH:5:1)

pooboy02:03:51

My core.clj:

(ns name)

(defn -main []
(println "Whats your name ?")
(def name read-line)
(str "Hi " "" name) ) 

noisesmith02:03:58

then call (name/-main)

noisesmith02:03:11

it's not called main, it's called -main

pooboy02:03:17

Beautiful thank you !

pooboy02:03:17

And if i want distribute this for others to use ..i need to package it into a jar ?

noisesmith02:03:23

yeah, jars are the normal way. But for others to use it, be sure you don't have a single segment namespace - make sure it has a meaningful ns with more than one part

noisesmith02:03:31

and also put it in a path that is relative to the ns

amcloud02:03:33

lein uberjar

noisesmith02:03:58

yes, that's the easy way to make a jar, but so far pooboy was explicit about how to do things without lein

amcloud02:03:28

Ah. Didn’t read far enough up the thread.

pooboy02:03:07

can i do it without lein?

noisesmith02:03:46

pooboy yeah - using the jar command line program - you can find out how to use that via google or the manual page, I have only used it minimally myself

noisesmith02:03:16

also most pople use their jars via maven, which gets more complicated and you start to see why people use leiningen

noisesmith02:03:11

maven requires certain conventions be followed, specific documents and formats and folders in the jar etc.

pooboy02:03:07

Thank you ! You guys have been very helpful

noisesmith02:03:59

it's refreshing to answer "how to do this with the simplest tools" rather than "what's the easy way" once in a while, heh

amcloud02:03:20

May I ask why you are avoiding lein?

pooboy02:03:43

And in the below code .. My core.clj:

(ns name)

(defn -main []
(println "Whats your name ?")
(def name read-line)
(str "Hi " "" name) ) 

pooboy02:03:17

When i run it .. i get .. user=> (name/-main) Whats your name ? "Hi clojure.core$read_line@19321e2" user=> ( def x read-line) #'user/x user=> x #object[clojure.core$read_line 0x19321e2 "clojure.core$read_line@19321e2"]

pooboy02:03:32

Why is the prompt not stopping for my input ?

noisesmith02:03:37

because read-line is a function, and functions are values

noisesmith02:03:42

to call functions, you need parens

noisesmith02:03:07

also, as an aside, def creates globals, it's OK for simple learning examples but breaks easily in real code - for local values there's let

noisesmith02:03:49

@suryapjr to be clear read-line is just a function (it has a weird name with a @ and number in it), (read-line) actually calls the function

noisesmith02:03:33

I am about to go take a bus home, I'm sure other people can help

pooboy02:03:44

Sure thing !

pooboy03:03:32

(ns name)

(defn -main []
(println "Whats your name")
(def name (read-line))
(str "Hi " "" name)



)

pooboy03:03:09

user=> (name/-main) Whats your name ? "Hi clojure.core$read_line@19321e2"

pooboy03:03:25

Why is the read-line function not getting called ?

mfikes03:03:03

@suryapjr That code works for me. Recommend using let instead of def inside the fn.

pooboy03:03:21

Let me try

pooboy03:03:43

Still getting :

Whats your name ?
"Hi clojure.core$read_line@19321e2"

mfikes03:03:34

Hmm. That looks like it is running your older -main from above.

mfikes03:03:11

Does it block and read a line of input?

pooboy03:03:41

No its not waiting for input

pooboy03:03:48

Let me reload the REPL

mfikes03:03:53

@suryapjr If you revise your code to use let instead of def it would look like this

(defn -main []
  (println "Whats your name ?")
  (let [name (read-line)]
    (str "Hi " "" name)))

nakiya03:03:15

I implemented A* algorithm to solve the n-puzzle problem. It works for 3x3 puzzles fine. However, when I try to solve a shuffled 4x4 puzzle, the browser runs out of memory. Here’s the core A* functions:

(defn- make-mm [vals]
  (into (sorted-map)
        (into []
              (map #(vec [(first %) (set (rest %))]) vals))))

(defn- A* [open closed dim]
  (when (not (empty? open))
    (let [[key node] (first-multi open)
          puzzle (first node)]
      [key node]
      (if (solved? (first node))
        (reverse (create-path node []))
        (let [open (dissoc-multi open (nth node 3) node)
              closed (conj closed puzzle)
              neighbors (get-neighbors puzzle dim)]
          (recur
            (reduce
              (fn [coll neighbor]
                (let [g (+ 1 (nth node 2))
                      f (+ g (heuristic neighbor dim))]
                   (assoc-multi coll f [neighbor node g f])))
              open
              (map #(when (nil? (get closed %)) %)
                neighbors))
            closed
            dim))))))

(defn solve [start dim]
  (let [closed #{}
        f-start (heuristic start dim)
        open (make-mm [[f-start [start nil 0 f-start]]])]
    (if-let [path (A* open closed dim)]
      (let [p1 (vec path)
            p2 (into [(first p1)] (pop p1))]
        (rest (map #(get %2 (.indexOf %1 0)) p2 p1))))))
(Full code can be found here: https://github.com/nakiya/npuzzle/blob/master/src/cljs/npuzzle/db.cljs) So when call (solve [5 1 4 6 7 3 8 2 0] 3), it returns (2 7 6 5 1 4 3 6 7 8 5 7 4 3 6 2 8 4 2 6 3 2 7 5 4 7 5 4 7 8) which are the tiles needed to be moved to get to goal position. What can I do to reduce memory usage? P.S. Of course, I can put the A* algorithm on server side. But I am asking about the general code here. I am new at clojure, so I want to know if I’m doing anything wrong.

pooboy03:03:07

@mfikes it worked with let !! Thanks !

mfikes03:03:28

It should also work with def

mfikes03:03:21

A consequence, though, is that each time you run the function, if you are using def it redefines a name var:

name=> (-main)
Whats your name
Mike
"Hi Mike"
name=> name
"Mike"
name=> (-main)
Whats your name
Surya
"Hi Surya"
name=> name
"Surya"

derpocious03:03:38

hey all, I'm having trouble using a nodejs library in a clojurescript project using leiningen

derpocious03:03:52

but I get this error:

Caused by: clojure.lang.ExceptionInfo: No such namespace: twit, could not locate twit.cljs, twit.cljc, or Closure namespace "twit" in file src/twitter_unfollower/core.cljs {:tag :cljs/analysis-error}

derpocious03:03:09

I've tried adding it to my project.clj

derpocious03:03:17

(defproject twitter-unfollower "0.1.0-SNAPSHOT"
  :description "Jim's bot"
  :url ""
  :dependencies [[org.clojure/clojure       "1.8.0"]
                 [org.clojure/clojurescript "1.8.51"]
                 [org.clojure/core.async    "0.2.395"]
                 [io.nervous/cljs-lambda    "0.3.5"]
                 [cljs-http "0.1.44"]]
  :plugins [[lein-cljsbuild "1.1.4"]
            [lein-npm       "0.6.0"]
            [lein-doo       "0.1.7"]
            [io.nervous/lein-cljs-lambda "0.6.6"]]
  :npm {:dependencies [[source-map-support "0.4.0"]
                       [xhr2 "0.1.4"]
                       [twit "2.2.9"]


                       ]}

  :source-paths ["src"]
  :cljs-lambda
  {:defaults      {:role "arn:aws:iam::954459734159:role/cljs-lambda-default"}
   :resource-dirs ["static"]
   :functions
   [{:name   "cljs-twitter-unfollower"
     :invoke twitter-unfollower.core/run-lambda}]}
  :cljsbuild
  {:builds [{:id "twitter-unfollower"
             :source-paths ["src"]
             :compiler {:output-to     "target/twitter-unfollower/twitter_unfollower.js"
                        :output-dir    "target/twitter-unfollower"
                        :source-map    true
                        :target        :nodejs
                        :language-in   :ecmascript5
                        :optimizations :none}}
            {:id "twitter-unfollower-test"
             :source-paths ["src" "test"]
             :compiler {:output-to     "target/twitter-unfollower-test/twitter_unfollower.js"
                        :output-dir    "target/twitter-unfollower-test"
                        :target        :nodejs
                        :language-in   :ecmascript5
                        :optimizations :none
                        :main          twitter-unfollower.test-runner
                        :npm-deps { :twit "2.2.9" }
                        :install-deps true}}]})

derpocious03:03:26

is there something else I'm missing?

derpocious03:03:10

I try to require it like a normal namespace

(ns twitter-unfollower.core
  (:require [cljs-lambda.util :as lambda]
            [cljs-lambda.context :as ctx]
            [cljs-lambda.macros :refer-macros [deflambda]]
            [cljs-http.client :as http]
            [cljs.nodejs :as nodejs]
            [cljs.core.async :as async :refer [<!]]
            [twit :as twit])
  (:require-macros [cljs.core.async.macros :refer [go]]))

mfikes03:03:51

@derpocious My only comment is that many developers are transitioning to using the new NPM dependencies capability built directly into ClojureScript 1.9.946

derpocious04:03:17

I would really like to be able to use it in this 1.8 project though

derpocious04:03:19

out of curiosity, are there any good articles on the new way?

derpocious04:03:41

thanks, I've read that article and added the :npm-deps, but I'm getting the same error 😕

derpocious04:03:43

I also found this nice clojure twitter api https://github.com/adamwynne/twitter-api, but it is not cljs so I don't think I can use it 😕

derpocious05:03:29

Very strange. I just tried adding another node library with [node-twitter "0.5.3"]

derpocious05:03:17

When I add that only to the project.clj :npm { :dependecies it does compile fine, and I even see the node package being downloaded in the console

derpocious05:03:51

but then when I try to require the namespace in my code it says it can't find the namespace 'node-twitter'

nakiya07:03:14

Is there a shorter or a more elegant way to do this?

(reduce #(if (even? %2) (assoc %1 %2 (+ %2 50)) %1) {} [1 2 3 4 5])
--> {2 52, 4 54}

nakiya07:03:59

Basically, I’m interested in the form:

(reduce #(if <condition> (assoc %1 %2 <calculation> %1) {} <collection>)

leonoel07:03:42

(->> collection
     (filter condition)
     (map (juxt identity calculation))
     (into {}))

rauh08:03:39

@duminda Shortest is probably #(conj %1 (when (even? %2) {%2 (+ %2 50)}))

rauh08:03:50

Elegant is: #(cond-> %1 (even? %2) (assoc %2 (+ %2 50)))

pooboy08:03:00

How to use clojure for scripting?

Empperi08:03:48

clojure itself isn't that great for it due to it's long startup time. It can be used though, just build an uberjar and then execute it. However, you can use ClojureScript for this via lumo https://github.com/anmonteiro/lumo

pooboy08:03:27

Cool. Thanks !

pooboy08:03:39

And.. What is arity overloading

Empperi08:03:13

; this
(defn foo
  ([x] (println x))
  ([x y] (println x y)))

Empperi08:03:36

now you can call foo with one or two arguments but no more

Empperi08:03:05

both calls end up into different function body where you can do different things if you so choose

Empperi08:03:41

I think the most common use case for it is something like this:

Empperi08:03:18

(defn hello
  ([] (hello "World"))
  ([n] (println "Hello," n)))

Empperi08:03:10

which will print "Hello, World" when called without arguments (hello) but you can call it also with an argument like (hello "Slack") which would print "Hello, Slack"

pooboy08:03:59

Very clear thanks !

pooboy08:03:52

It's amazing how clojure is making a lot of sense to me now ...

pooboy08:03:08

Earlier I was petrified of looking at its parentheses

Empperi08:03:39

first you learn to not see the parenthesis, then you learn to love them and after that no other syntax makes any sense anymore

pooboy08:03:10

Lol...i would love to be in that mode !

pooboy08:03:28

And when people say the clojure being lisp is extensible,what do they mean?

sundarj10:03:54

the rest of the stuff on those links is worth reading too 🙂

Empperi08:03:42

well, for example defn in clojure is just a macro

Empperi08:03:01

Clojure has I think only 13 language reserved words or characters

Empperi08:03:11

rest of the language is built with macros

Empperi08:03:16

and functions

timo09:03:28

how do you debug problems with clojure-compiler concerning externs?

timo10:03:36

something like that

Uncaught TypeError: xK is not a function
    at app.js:1227
    at app.js:1334

pooboy10:03:40

ns fun)

(defn -main []
(println "Hello")
(println "What do u want to add to your list? ")
(def item (read-line))

(def mylist '())

(conj mylist item)

(println mylist))

pooboy10:03:46

This code gives me the below output user=> (load-file "core.clj") #'fun/-main user=> (fun/-main) Hello What do u want to add to your list? egg () nil user=>

pooboy10:03:56

Why is egg not added to my list

joelsanchez10:03:20

because clojure is a functional language, you can't "change" mylist. try (println (conj mylist item))

joelsanchez10:03:23

using def to hold changing values is not a good practice, btw. look for atom

pooboy10:03:21

Immutability..right :)

pooboy10:03:33

Need to get oop out of my head

joelsanchez10:03:45

a quick example of what I mean

user=> (def item (atom nil))
#'user/item
user=> (reset! item (read-line))
Hi!
"Hi!"
user=> (def mylist [])
#'user/mylist
user=> (println (conj mylist @item))
[Hi!]
nil
user=> 

lispyclouds10:03:50

@suryapjr This is more of a imperative style of writing code. In term of statements; which inherently use state. I would suggest seeing https://www.infoq.com/presentations/Are-We-There-Yet-Rich-Hickey to get the whole Functional style of thinking. Would be helpful in learning Idiomatic Clojure and FP

lispyclouds10:03:51

For me seeing this before learning Clojure helped a lot 🙂

pooboy10:03:47

what about def vs let

sundarj10:03:49

def defines a globally-available var at the top level of a namespace. let defines a local constant that can only be used inside its body

sundarj10:03:52

user=> (def a 1)
#'user/a
user=> a
1
user=> ((fn [] a))
1
user=> (let [a 2] a)
2
user=> a
1
user=> ((fn [] a))
1

joelsanchez10:03:52

docs https://clojure.org/reference/atoms* examples https://clojuredocs.org/clojure.core/atom basically a reference to a value, which you can update in a thread-safe way ("atomically")

timo10:03:39

Hi again! When using cljsjs-packages, do I need to add their externs in the uberjar-profile in my luminus-project?

timo10:03:46

or is it automagic?

hawari10:03:56

Hi everyone, is there a function or a library already exists to insert something on every nth entry in collection? Something like

(insert-nth 2 [1 2 3 4] "hello")
=> [1 2 "hello" 3 4 "hello"]

rauh11:03:17

@hawari.rahman17

(let [n 2
      xs [1 2 3 4]
      in "hello"]
  (into []
        (comp (partition-all n)
              (mapcat #(conj % in)))
        xs))

hawari11:03:15

That's way simpler than I come up with now, please let me digest that now @rauh

hawari11:03:29

I've seen the documentation on into, I can't really understand what the xform part does? Could you explain it to me @rauh?

hawari11:03:08

Thanks @sundarj, I'll check it out

sundarj11:03:47

(into [] (comp (partition-all n) (mapcat f)) coll) is equivalent to (into [] (->> coll (partition-all n) (mapcat f))

sundarj11:03:01

but is more efficient since it does all of the transformations in a single step (no intermediate collections are generated)

hawari11:03:59

Why does the equivalent is partition-all being used first? If I evaluate ((comp str inc) 4) it returns "5" instead of an error, meaning that 4 is applied to inc first then str right?

sundarj11:03:37

comp always composes the functions passed in from right to left (transducers are functions). it's just that transducers have functions nested in functions, and due to the way those nested functions specifically work, they actually end up applied from left to right

sundarj11:03:06

even though they're still composed from right to left

hawari11:03:44

Okay, I think I'll need to understand transducers first then

sundarj11:03:06

yeah, it's just a quirk of the way they work

hawari11:03:55

Well, it seems that I learn something new every day with clojure 😁

sundarj11:03:09

haha! indeed :~)

hawari11:03:46

Especially with people like you going out of their way helping newbies like me

sundarj11:03:18

happy to help (where i can) 🙂

hawari11:03:49

I'll watch the video, thank you very much @sundarj

sundarj11:03:13

no problem!

sundarj11:03:00

ah, i seems there's only one still on there. you can find the rest here if you want: https://tbaldridge.pivotshare.com/categories/transducers/2426/media

hawari11:03:31

Gonna need all night to binge watch it

sundarj11:03:08

https://www.youtube.com/watch?v=6mTbuzafcII this talk uses a real-world metaphor to explain them, if you find that more helpful than seeing code

hawari11:03:45

Yeah, I'm watching the rich's one right now

mfikes12:03:47

@hawari.rahman17 And if n is small you could get away with something like

(let [xs [1 2 3 4]] 
 (interleave (take-nth 2 xs) (take-nth 2 (rest xs)) (repeat "hello")))

sundarj12:03:50

@mfikes here's the 'alternative' version i came up with: (apply concat (interleave (partition 2 [1 2 3 4]) (repeat ["hello"])))

mfikes12:03:25

Yes, that is nice too @sundarj 🙂

mfikes12:03:22

It feels like interleave is fairly close to the original question, and when composed with partition you can arrive at a solution

sundarj12:03:57

yeah, though with partition-all you end up with an extra "hello" if the input is too long, and with partition you end up with the remainder being swallowed

sundarj12:03:40

suppose a butlast can be used in the partition-all case

mfikes13:03:35

@sundarj I just realized your solution can be golfed a litter further with flatten, which is getting pretty succinct 🙂

(flatten (interleave (partition 2 [1 2 3 4]) (repeat "hello")))

sundarj13:03:26

ah, right! nice one 🙂

mfikes13:03:47

Hah. These things take a while to see, but they are satisfying IMHO. 🙂

sundarj14:03:17

that's for sure!

mfikes13:03:02

Summarizing, this solution is appealing because it is easy to read, while I bet the solution given by @rauh is much more efficient.

mfikes13:03:32

For a fair comparison with his solution:

(let [n 2
       xs [1 2 3 4]
       in "hello"]
  (flatten (interleave (partition n xs) (repeat in))))

mfikes13:03:03

simple-benchmark in Planck and Lumo show Rauh's running in 2/3 the time as the flatten approach in JavaScriptCore, but 3 times in V8. Hrm. I guess YMMV.

hawari03:03:25

Sorry for replying so late, and wow, I didn't expect for people to be so thoroughly helpful on my question. You guys really are awesome!

Nikos16:03:55

Hey peeps, I'm in the process of setting emacs up for Clojure. I'm coming from Dr.Racket and there new lines get automatically indented when inside brackets. In emacs not, unless I press tab or C-I.

Drew Verlee17:03:44

@nikoszp There is probably a couple ways to handle parens. * paredit * parinfer are two that come to mind. I’m not sure how to autoformat in emacs off the top of my head.

noisesmith17:03:59

@mfikes the one thing about flatten is that it doesn't respect your input datatype, in most cases it can be replaced with apply concat (which also will perform better) - or a cat transducer

noisesmith17:03:16

or even mapcat

Nikos17:03:56

I've been fiddling with the "Clojure indent style" in the customization buffer but it doesn't seem to change anything. Thanks @drewverlee I'll have a look.

noisesmith17:03:30

@nikoszp @drewverlee for making things indent properly, there's something like electric return that makes newline indent properly

noisesmith17:03:10

I've had extremely poor experiences with co-workers abusing parinfer and I'd even advise counting parens by hand before considering parinfer

sundarj17:03:54

i haven't touched parinfer/paredit yet. most people seem to recommend parinfer for newbies, do you instead recommend paredit?

noisesmith17:03:06

yes, paredit, and/or rainbow-parens

noisesmith17:03:53

the bad thing with parinfer is that with a shared code base, someone can accidentally check in weird indentation (it happens...) and then parinfer user loads the file and makes all the parens move to match indent which - always breaks everything

Drew Verlee17:03:13

I believe that problem is fixed in new versions.

Drew Verlee17:03:29

Which aren’t on emacs -_-

noisesmith17:03:48

that would be nice - FWIW I don't htink it was a parinfer bug, it was a user workflow bug (maybe?) anyway the fact that parinfer makes things like that easy is frustrating

noisesmith17:03:27

also the fact that people just check files into git without doing a diff by diff audit of what they are checking in

noisesmith17:03:39

CO WORKERS ARE TRYING TO MAKE ME DIE YOUNG

Drew Verlee17:03:52

Yea. that problem sort of exists in every ecosystem to some extent. I think that structurl changes > parinfer as well. But its a bit of a mental leap that i’m not ready to invest in at this stage. e.g i’m not going to stop what i’m doing to figure out what combo of slurps and barfs i need…

sundarj17:03:10

i suppose the fact parinfer does paren-matching implicitly means it's bound to cause issues like that

sundarj17:03:37

i've used rainbow parens before, i love it

Drew Verlee17:03:11

On this topic, i wouldn’t let great be the enemy of good. If your used to ruby and python which put a heavy emphasis on indentation, then using parnifer sort of naturally does what you want.

Drew Verlee17:03:27

I dont have co-workers using clojure.

noisesmith17:03:37

right, just don't check garbage changes in to code others have to deal with :P

sundarj17:03:10

to err is human; if a tool can't handle mistakes it's a flawed tool imo

Drew Verlee17:03:14

Noisesmith, is there anything substianantly better then paredit for emacs?

noisesmith17:03:50

not sure? I had to flee emacs after over a decade of usage, I'm a vim user now

gonewest81817:03:11

In theory you could add a formatting check in your CI, e.g. load the file in an offline emacs session with parinfer mode and watch what happens. If parinfer wants to move any parens then abort the build. That may feel heavy-handed, but not unprecedented.

noisesmith18:03:35

there’s also cljfmt check which is actually designed for showing you if formatting is bad

gonewest81819:03:17

Right. Could there be corner cases where parinfer and cljfmt disagree? I have no idea.

Nikos17:03:41

@noisesmith It's working! Thank you!!

Will17:03:25

How would I convert a sequence to a vector so I can call mapv on it? I tried this but it didnt work (mapv :a (into [] (-> checks (into {}))))

dpsutton17:03:38

mapv returns a vector, it doesn't require one as input

dpsutton17:03:15

(mapv inc (range 4)) == >[1 2 3 4]

dpsutton17:03:27

note that (-> checks (into {})) is (into checks {}) which doesn't seem to do a lot of good

Will17:03:11

Thanks! I didnt notice that

dpsutton17:03:44

play in the repl a lot. use doc and source. and run experiments on vectors like [:a :b :c]

Will17:03:12

I have what I think is a sequence of vectors of maps which I can’t figure out how to turn into a vector of maps

sundarj17:03:17

@josmith2016

user=> (reduce (partial reduce conj) [] '([{}] [{}]))
[{} {}]
user=> (into [] cat '([{}] [{}]))
[{} {}]

Will18:03:16

Thanks @sundarj! that worked

nakiya18:03:37

From this server:

(ns npuzzle.handler
  (:require [compojure.core :refer [GET POST defroutes]]
            [compojure.route :refer [resources]]
            [ring.util.response :refer [resource-response response not-found]]
            [ring.middleware.reload :refer [wrap-reload]]
            [ring.middleware.json :refer [wrap-json-response wrap-json-body wrap-json-params]]
            [ring.middleware.keyword-params :refer [wrap-keyword-params]]))

(defroutes routes
  (GET "/" [] (resource-response "index.html" {:root "public"}))
  (POST "/ajax/:params" [params] (println params))
  (resources "/"))

(def handler (-> #'routes wrap-json-response wrap-json-params (wrap-json-body {:keywords? true})))
I get the below error when /ajax is POSTed to with {:puzzle [7 5 3 2 4 8 0 1 6]} as payload: java.lang.IllegalArgumentException: Cannot open <{:puzzle [7 5 3 2 4 8 0 1 6]}> as an InputStream. Can someone help me understand what’s going on?

mathpunk19:03:54

I have values that will always be in one order. I'm looking to turn them into a map. This works (apply assoc (conj (interleave [:a :b] [1 2]) {})) but I'm betting there's something more idiomatic. Any suggestions?

noisesmith19:03:58

(into {} (map vector [:a :b] [1 2])) - this is idiomatic, and performs better

alexk19:03:11

I’d argue (zipmap [:a :b] [1 2]) is even more idiomatic because it’s purpose-built

dpsutton19:03:47

i don't think that makes it more idiomatic.

alexk19:03:31

> using, containing, or denoting expressions that are natural to a native speaker

dpsutton19:03:30

the standard idiom is the one noisesmith posted above. or at least that's what i've seen the most and is easily recognized by me. others might vary. but i do think a standard pattern is more idiomatic than a function that does exactly what you are looking for

alexk19:03:37

Ah I know what you mean - like somebody using not-empty instead of seq because it’s better aligned with the intent

dpsutton19:03:15

sorta. idiom to me is just common patter. it's easy to write correct code that just doesn't look like what most people write is all. its not better or worse. think "pythonic".

dpsutton19:03:06

(-> thing :a :b) vs (get-in thing [:a :b]). one does exactly what you need. one is more general but seen quite a bit more i think

ghadi19:03:26

nah zipmap is more common

noisesmith19:03:44

yeah I just forgot about zipmap (I rarely need it) so I just showed the pattern I use for stuff like that

noisesmith19:03:53

agreed zipmap is common and the right thing to use

tdantas22:03:19

hey guys, quick help I’m trying to hook into repl :caught like that

(clojure.main/repl :caught (fn [t] (pprint t)))
but everytime I try this I’m messing with my repl

tdantas22:03:45

for instance, could not find exit symbol

tdantas22:03:02

any idea why this is happening ?