Fork me on GitHub
#beginners
<
2017-09-19
>
Simon08:09:28

I'm confused about defmulti

Simon08:09:42

#object[Error Error: No method in multimethod 'cljs.user/query-dispatcher' for dispatch value: ["Select" ["first_name" "like" "Sitges"]]]

Simon08:09:03

I want to match on the "Select" in q but it does not work

Simon08:09:35

I feel like I've followed the examples

skarmeta08:09:18

If I have a list of things, and want to construct a map where the keys are each thing, and the values are some function applied to each thing, how do I do it? Like this in Python:

{k: f(k) for (k, _) in ['a', 'b', 'c']}

leonoel08:09:50

(zipmap things (map f things))

skarmeta08:09:53

Why am I getting an arity exception when an empty string is passed in as a second argument to a function that takes two arguments? nucleotide-count/count \A, "" throws actual: clojure.lang.ArityException: Wrong number of args (1) passed to: nucleotide-count/count where it's defined as:

(defn count
  "counts instances of base in sq; throws if not a real nucleotide"
  [base sq]
  (count (filter #(
        (assert (contains? bases %))
        (= base %)) sq))
  )

jumar08:09:29

@purohit the problem is that you're shaddowing the clojure.core/count function, but you're still trying to use that core function inside your function. The count which are you trying to invoke in the function body is your count function, not clojure.core/count

skarmeta08:09:55

So do I need to disambiguate by calling clojure.core/count in my function body?

jumar11:09:57

you should - or rather rename your count function to something else

Simon08:09:50

I'm doing all of the above in proto-repl, and thought I had copied code over directly from a colleague who had made it work in their environment (emacs I think)

jumar08:09:05

@hotbelgo I tried your code and it works for me

Simon08:09:23

oh, so I don't know how to make proto repl work then

jumar08:09:38

Try it in plain clojure repl first. Are you sure you evaluated everything properly?

Simon08:09:00

I've cut and paste the whole thing

Simon08:09:09

I've ctrl+,+b each part

Simon08:09:36

yikes, how do i do that

Simon08:09:34

i'm actually trying to update someone elses code and I'm seeing the same error when I pass data to this multimethod

jumar08:09:40

I don't use protorepl, so I don't know exactly how to eval things there. However, in most editors, you can easily eval the whole file/buffer. That way it should work. Maybe ask in #protorepl if you have specific problems with it. You can also try to select everything and eval it with ctrl-alt-, s (see https://atom.io/packages/proto-repl - Sending a selection).

jumar08:09:04

Also notice, that once you define a multimethod, it's not that easy to redefine it (this is because defmulti uses defonce to define var that holds the multimethod). You can use ns-unmap to remove defmulti definition.

jumar08:09:21

It's possile to reproduce your error with something like this:

;; Notice I incorrectly use sequence
(defmulti query-dispatcher sequence)
(defmethod query-dispatcher "Select" [[_select [lhs op rhs]]]
  (str lhs " " op " " rhs))

(def q  ["Select" [
                   "first_name" "like" "Sitges"]])
(query-dispatcher q)
;;=> 
IllegalArgumentException No method in multimethod 'query-dispatcher' for dispatch value: ("Select" ["first_name" "like" "Sitges"])  clojure.lang.MultiFn.getFn (MultiFn.java:156)

;; Now I want to fix it:
(defmulti query-dispatcher first)
;; But I have to unmap query-dispatcher first
(ns-unmap *ns* 'query-dispatcher)
;; and then re-eval everything.

Simon08:09:08

ah, yes, what you say about renaming rings a bell

Simon08:09:19

and i managed to make it work on a different computer

Simon08:09:49

---- Could not Analyze <cljs form> line:1 column:1 ---- nth not supported on this type: Symbol 1 (ns-unmap ns 'query-dispatcher) ^--- ---- Analysis Error ----

Simon08:09:44

when I was being taught we just renamed stuff

Simon08:09:55

but I changed to query-dispatcher3

Simon09:09:06

did ctrl+, l on each part

Simon09:09:08

and end up with

Simon09:09:14

----  Compiler Warning on   <cljs form>   line:1  column:2  ----

  Use of undeclared Var cljs.user/query-dispatcher3

  1  (query-dispatcher3 q)
      ^--- 

----  Compiler Warning  ----
#object[TypeError TypeError: Cannot read property 'call' of undefined]

Simon09:09:29

ok, resarted everytihngf and it works

Simon09:09:38

wow - this is hard

skarmeta10:09:07

How do I map a function to a collection but also pass another argument? Like I want (map my_fn my_seq extra_arg) because my_fn takes two args

skarmeta10:09:41

I thought about using partial functions but the argument I'm adding is in the second place instead of the first one

skarmeta10:09:40

Guess I have to use an anonymous fn

skarmeta10:09:35

How do I consume two sequences of equal length and run some function on each pair of objects? Like if I have

(def a '(1 2 3))
(def b '(4 5 6))
And I want to run pairs like 1, 4 and 2, 5 [etc] to some function I have

Prakash10:09:44

@purohit mapv should do it

skarmeta11:09:07

Perfect, thanks!

Aron13:09:07

i have these random brainfreezes regarding anything clojure. i want to evaluate/test/try out two sql libs, how should i do it? create a completely empty project for this? seems like a lot of work? using something that's already filled up seems weird

rcustodio13:09:53

I do all my brainstorm there

madstap13:09:15

@ashnur I usually just have a project for screwing around in, made with lein new, It's the easiest way. There's also https://github.com/rkneufeld/lein-try and if you use boot it should be easy enought to add deps to the repl.

jumar15:09:10

@ashnur +1 for madstap's approach. I also have a single project (https://github.com/jumarko/clojure-repl-experiments) where I play with random clojure stuff. Usually, I have this project open in Spacemacs with cider-repl running all the time, so I can quickly test anything I want. Using cider + clj-refactor it's very easy to quickly add dependency to the running repl/project: cljr-add-project-dependency.

rcustodio13:09:06

interesting that lein-try

ghadi14:09:46

@ashnur If you're on osx, I think the easiest thing now is to use the new official clj tool. brew install clojure

Aron14:09:26

windows or linux

ghadi14:09:36

coming soon to a package manager near you

Aron14:09:40

i am not a rich person 🙂

ghadi14:09:46

we're not there quite yet 😃

Aron14:09:16

i just did lein new sandbox for now

ghadi14:09:36

{:deps {org.clojure/clojure {:type :mvn :version "1.9.0-beta1"}
        org.bouncycastle/bctsp-jdk14 {:type :mvn :version "1.38"}}}

ghadi14:09:49

that's the new deps.edn format for the clj tool

ghadi14:09:17

took me a moment to find, but the docs for that tool moved here: https://clojure.org/guides/deps_and_cli

Alex Miller (Clojure team)15:09:06

fyi, a lot of stuff on that page is undergoing big changes atm

seancorfield16:09:26

@ashnur Might be worth looking at boot since you can first up boot repl and then add new dependencies on the fly and test libraries without needing to restart your REPL (and without needing a project at all).

hmaurer16:09:26

@seancorfield how do you add dependencies on the fly? set-env! with the new vector of dependencies?

Aron16:09:42

i was afraid of boot because most of the tools i need are explained in terms of lein

hmaurer16:09:22

What is the meaning of () in the expression (){:x 42} ?

hmaurer16:09:29

(this was generated by honeysql)

hmaurer17:09:07

Oh wait, nevermind. Just some repl anomaly

seancorfield17:09:38

@hmaurer I use merge-env! but, yes, you add new :dependencies to the environment and Boot loads them, then and there.

chris17:09:27

@ashnur I find boot much simpler to understand than lein, fwiw

seancorfield17:09:27

@ashnur At work we switched from lein to boot about a year ago. No regrets 🙂

chris17:09:34

it's less magical

Aron17:09:40

tell me, how much less is that? like, from the normal clojure level of magic, which is OVER9000, how much does it take off? 🙃

chris17:09:09

haha, it uses that clojure magic to build composable pipelines

chris17:09:49

lein plugins just use project.clj for every single thing and it makes a mess

seancorfield17:09:04

Boot is "just functions" (well, "tasks", but you extend Boot and control Boot with plain ol' functions). Leiningen is declarative so you have project.clj and everything else is implicitly executed as plugins etc.

Aron17:09:38

can you do everything with boot that is/was done by lein?

seancorfield19:09:44

@ashnur I think Boot can do a lot more than Leiningen. Extending Leiningen (with plugins) was always hard so replacing a full Ant-based build script with Leiningen was next to impossible. Replacing it with Boot is a lot more straightforward. We're doing a lot of stuff with Boot now that was extremely hard with Leiningen.

seancorfield19:09:21

For example, we keep all our dependencies in EDN files and we all "pin" versions of common libraries in a .properties file, then we have functions in our build.boot file that stitch all that together when constructing the final list of :dependencies. That sort of programmatic stuff is ugly/hard/impossible in Leiningen.

Aron12:09:12

this sounds really good, however it's mostly about stuff i am not dealing with now. it's very convenient for me as a beginner that i just have to copy paste into project.clj

Aron12:09:43

also, lot of tutorials and readmes only talk about lein and it's not clear to me how can i take a project.clj for lein and make it into a boot project

chris12:09:47

yeah that definitely makes sense

seancorfield16:09:54

I'm writing a blog post aimed at beginners that will address this. It'll show how to use Boot to do simple stuff in a project that assumes Leiningen. Might take me a while to finish it tho'.

Aron11:09:32

i was thinking, "build tool" is kinda misleading isn't it? it builds in the sense of from source to binary, but someone coming from javascript or php will look and say, ok, so i am building projects with this. or is it both?

Aron11:09:59

and usually, the questions that I can't find answers googling are the hardest to get answered on slack too 🙂

Aron12:09:26

still don't know how to import and use it though. it's not explained anywhere

seancorfield16:09:14

@ashnur Not quite sure what you're asking about -- but Java interop is covered here: https://clojure.org/about/jvm_hosted -- what questions does that leave unanswered?

Aron16:09:53

that's like the third url today that is called THE docs for java interop 🙂

Aron16:09:13

i got some help on IRC, used a different maven repo, and could import the class

Aron16:09:48

(import 'net.sf.jsqlparser.parser.CCJSqlParserUtil) this was what i was searching

seancorfield16:09:54

If you were clearer about your problem statement, I could give clearer answers 🙂

Aron16:09:31

if i knew how to be "clearer" i would've said it. i am sorry that i am dumb, but that's kind of the way beginners are 🙂

Aron16:09:42

not sure why you have to say such things though, i didn't blame you for not helping, i am grateful that you try to help. so why you have to attack my inaptitude, i already know i am not clear enough, i will probably never be clear enough in these situations 😞

seancorfield16:09:13

I wasn't attacking -- I was just teasing that I can't be as helpful as I'd like to be, because I wasn't sure what you were asking. I didn't mean to come across as rude 😞

Aron16:09:56

np then, sorry for being perhaps too sensitive, i am trying to ask clear questions but often trying is not enough

seancorfield17:09:43

☝️:skin-tone-2: Yes, this.

hmaurer17:09:53

@seancorfield neat. By the way, I’ve a bit of an unrelated question. I have been told that Spring Boot uses a different technique than standard “uberjars”. Instead of merging all class files into a single jar, they generate a jar containing the librairies jars in a folder, and load them dynamically

hmaurer17:09:59

is that something doable with boot?

hmaurer17:09:28

(and yes, I am a beginner and also found boot much simpler to understand after switching to it)

seancorfield17:09:32

@hmaurer I don't know enough about Spring Boot to understand what you're suggesting.

hmaurer17:09:02

> Java does not provide any standard way to load nested jar files (i.e. jar files that are themselves contained within a jar). This can be problematic if you are looking to distribute a self-contained application that you can just run from the command line without unpacking. > To solve this problem, many developers use “shaded” jars. A shaded jar simply packages all classes, from all jars, into a single ‘uber jar’. The problem with shaded jars is that it becomes hard to see which libraries you are actually using in your application. It can also be problematic if the same filename is used (but with different content) in multiple jars. Spring Boot takes a different approach and allows you to actually nest jars directly.

seancorfield17:09:12

shrug No idea... nor do I have any idea why that would matter...

Alex Miller (Clojure team)17:09:47

both approaches have downsides. really, creating uberjars at all is just a bad thing. if only it weren’t so damn convenient.

Alex Miller (Clojure team)17:09:22

the shaded uberjar runs the risk of clobbering, particularly with manifests and other similarly tricky parts of jar files

Alex Miller (Clojure team)17:09:03

using a jar-in-a-jar requires special classloader and url support for the jvm to understand what you’re doing

Alex Miller (Clojure team)17:09:50

I’m not aware whether the latter works in a clean way with Clojure (you’d need something more than just Clojure to make that work)

hmaurer17:09:23

@alexmiller I see; thanks for the details!

rcustodio18:09:27

A simple pool, who uses lein and who uses boot?

rcustodio18:09:50

I started to read about boot now, but for libraries I think lein is better

Alex Miller (Clojure team)18:09:48

we do this poll every year and it’s a good sample size

seancorfield19:09:42

It'll be interesting to see how much ground Boot has made in the next survey. Leiningen will continue to be the default choice for a lot of people coming into Clojure because it's what (nearly?) all the books recommend right now.

cgore19:09:58

All of our corporate tooling assumes lein, so boot would require a lot of support work for us, and so we’ll probably stay with lein unless there’s a huge advantage. I’m sure a lot of other places are the same.

Jim Rootham19:09:15

I am getting mugged by startup issues. I have a project.clj:

Jim Rootham19:09:19

(defproject voting "0.1.0-SNAPSHOT" :description "Cabal voting back end" :url "http://example.com/FIXME" :license {:name "Eclipse Public License" :url "http://www.eclipse.org/legal/epl-v10.html"} :dependencies [[org.clojure/clojure "1.8.0"][http-kit "2.2.0"]] :main ^:skip-aot voting.core :aot [voting.core] :target-path "target/%s" :profiles {:uberjar {:aot :all}})

seancorfield19:09:05

(you can use triple-backtick to format code when pasting small fragments here @jrootham)

Jim Rootham19:09:13

I ran lein deps after putting in the [http-kit "2.2.0"] and it said it downloaded them

Jim Rootham19:09:34

Although the time it took was a clue that it didn't

Jim Rootham19:09:27

I cannot find http-kit in my project (created with lein app voting)

seancorfield19:09:02

JAR files are downloaded to your local Maven cache in .m2/repository in your home directory. They are not added to the project itself.

Jim Rootham19:09:10

`(defproject voting "0.1.0-SNAPSHOT" :description "Cabal voting back end" :url "http://example.com/FIXME" :license {:name "Eclipse Public License" :url "http://www.eclipse.org/legal/epl-v10.html"} :dependencies [[org.clojure/clojure "1.8.0"][http-kit "2.2.0"]] :main ^:skip-aot voting.core :aot [voting.core] :target-path "target/%s" :profiles {:uberjar {:aot :all}})

seancorfield19:09:53

@jrootham You'll need to adjust a Slack preference so pressing enter inside backticks does not send the message: https://www.dropbox.com/s/z9hsl1vtxn509uk/Screenshot%202017-09-19%2012.27.59.png?dl=0 (I don't know why this isn't Slack's default -- it's very counter-intuitive)

Alex Miller (Clojure team)19:09:28

I think he just missed the closing triple back tick

Jim Rootham19:09:51

Sorry, not familiar with that idiom

seancorfield19:09:11

Back to your problem... The JAR files don't get added inside your project tree.

seancorfield19:09:52

(and the time taken is because a lot of JAR files will be downloaded the first time you reference some new libraries)

Jim Rootham19:09:47

OK, I have found the library, so it did download, I now have the newbie issue of how to use them in my code, in the lein repl should (:require 'http-kit) work, and how do I tell?

seancorfield19:09:04

When you start a REPL with lein repl inside the voting project directory, it will have the dependencies declared in project.clj and you can (require 'http-kit.whatever) namespace.

seancorfield19:09:27

(note: no : for the require function -- it has a : inside the ns form in your source code tho')

Jim Rootham19:09:11

(require 'http-kit) gets me a file not found message, your last answer suggests I should be looking for a namespace inside http-kit

Alex Miller (Clojure team)19:09:39

confusingly, the name of the artifact and the names of the namespaces inside an artifact, do not necessarily have any correlation (although usually the artifact name is part of the namespace name)

Alex Miller (Clojure team)19:09:07

in this case, the namespaces of interest are either org.httpkit.server or org.httpkit.client

Jim Rootham20:09:32

Ah, it looks closer, use instead of require. The demo works in the repl. Now for actual code.