Fork me on GitHub
#beginners
<
2017-04-26
>
sb06:04:28

@sakalli if you come from the R area, that will be a little bit hard trip. I created many thing with R, like Apache without PHP and R.. websites. Here needed very different thinking

sakalli11:04:40

sb: thanks! that is my sense as well. I was referring to the functional aspects of r. Apply family functions and also some of the tidyverse stuff. I have for example literally not needed to write a for loop in past few years. (Although there are of course cases where one does need them)

sb11:04:17

Hello @sakalli, do you need at least 2-3 months to get great results with Clojure. I created few mistake I started with Nginx-Clojure.. so here is many “black hole” for a beginner.. so after 6 months, I dropped out.. and I use now httpkit, I think.. that is more closer for you too. Nginx-Clojure needed more java knowledge, lot of unit tests.. and very hard to manage sessions (really! - not just self-manage or Redis.. really manage..). Don’t give up! .. in this days, I don’t want to use R.. just Clojure. I really like this!

sb11:04:24

Plus read lot of book, if you have time. Ton of great book in the market..

sakalli21:04:53

sb: cheers! Appreciate all the tips & encouragement 🖒

Chris Bidler14:04:28

Ha! I figured out my issue from yesterday. (zip/root) already returns the node view of the root node so passing it to zip/node correctly returns nil just like any other argument that isn't a zipper.

Chris Bidler14:04:51

I feel a lot better now that I understand what was wrong with my code there hehe

matan18:04:36

question: can one require or use a namespace from within a function?

matan18:04:58

I would like to stop sticking all my namespace imports in the topmost ns of some of my source files

matan18:04:09

It may seem easier to move functions around source files, eschewing the Java-ish notion that all imports equally belong throughout a source file. So not sure I should give up so fast

matan18:04:39

Particularly helpful when spiking things, or when refactoring

dominicm18:04:17

@matan you'll be giving up the dependency tree, particularly the one that is used by tools.namespace in order to reload dependencies in order. I'm pretty sure it doesn't work in cljs either.

mobileink18:04:02

@matan you can always write a fancy macro that requires stuff. 😉

Alex Miller (Clojure team)18:04:04

it’s tricky to make those work in the ns macro though

mobileink18:04:13

ps. ns != source file

matan18:04:22

thanks for all the considerations

mobileink18:04:03

you can always bind \ns\ and then (require... ). i have use cases for this, but then i'm meta-programming.

matan18:04:51

as a practice I'll be using for fast flexible spiking, I will practice this now and then, but I am not sufficiently familiar with require to follow why :as would not work for me:

(defn foo []
  (require '[ :as io])
  (let [paraphrases (io/file (io/resource "samples/paraphrases.txt"))]
    (-> paraphrases slurp println)
))

matan19:04:29

no syntax highlighting around here I guess 😝

matan19:04:24

The runtime wants me to use the fully qualified path to io, i.e.

matan19:04:00

So I wonder why :as isn't working for me up there

dpsutton19:04:17

and you're calling that function from a different namespace?

matan19:04:12

Oh sorry about that, no I do not call it yet at all, but it breaks apart already during compilation (if I can say "compilation" in clojure in this context, probably I shouldn't)

noisesmith19:04:43

the require happens when the function runs, the resolution of io/foo happens at compilation time

noisesmith19:04:51

so it’s out of order

noisesmith19:04:15

@matan saying compilation is fine, clojure always compiles code before running it

matan19:04:31

I suspected that. So other than including the require in a ns, nothing like this would ever work right?

noisesmith19:04:55

@matan there’s resolve, which basically screams “I am doing something foolish right now” but it works

mobileink19:04:02

you can always use alias.

noisesmith19:04:05

it’s a hack tool, for a hack task, a perfect fit

noisesmith19:04:33

@mobileink same problem with alias, it runs at runtime, so it doesn’t help the compilation error

noisesmith19:04:38

@matan what you are trying to do is fundamentally against the grain of clojure usage of namespaces - it’s possible but it won’t be pretty, and it will fail in unexpected ways

matan19:04:05

yes I understand that

noisesmith19:04:07

if your issue is ease of refactoring, there’s a lein tool, slamhound, that can figure out what requires need to be added to your ns block to fix your namespace

matan19:04:14

I just move stuff around source files a lot

matan19:04:30

@noisesmith I wonder what people do before unleashing slamhound against their source directory 🙂

matan19:04:54

I guess relying on a git stash or commit would be a good idea 😉

mobileink19:04:14

i could swear i've done this. must've been a macro.

noisesmith19:04:44

@matan for things like that I run git add and make sure everything is staged - that way any changes made since the add are unstaged, so I can review them

rubek19:04:50

Is there a clojure.core function to map the values of a map? so that for a map

{:a val1 :b val2}
and a function f I get
{a (f val1) :b (f val2)}
? I found a nice list comprehension on http://stackoverflow.com/questions/1676891/mapping-a-function-on-the-values-of-a-map-in-clojure but it feels like there should be some kind of map-values function or other?

noisesmith19:04:53

rather than making a “noise” commit in my history

noisesmith19:04:29

@rubek amazingly, this does not exist in clojure.core - but specter provides this and much more

matan19:04:43

@noisesmith thanks for sharing 🙂

matan19:04:03

to slamhound (now that I realize bringing in imports into scope within a function is a lost cause)

matan19:04:15

nice tool, for the lazy isn't it?

matan19:04:50

it just heuristically adds missing imports doesn't it?

noisesmith19:04:27

yeah, pretty much - but be aware require isn’t import, they both exist and they do different htings (and slamhound helps with both)

matan19:04:21

yes I know thanks, just sloppy writing

matan19:04:38

thanks again!

tbaldridge19:04:16

@rubek, I just do (zipmap (keys mp) (map f (vals mp)))

rubek19:04:35

Whoa thanks @noisesmith - but I guess I’ll stick to plain clojure for this. Specter seems useful but a bit too powerful for my hacky parser script 🙂

rubek19:04:20

@tbaldridge That’s actually really really neat! Looks much nicer than the for statement from SO

rubek19:04:15

And another question, sorry: I’ve got strings like “09” and “14" and so on and want to read-string them to numbers. Unfortunately, read-string doesn’t seem to like leading zeroes. Is there a better way to read numbers with a leading 0 than to drop all 0s from the String?

Alex Miller (Clojure team)19:04:01

(that will also accept negatives though btw)

rubek19:04:42

oh parseLong seems great! I was very close to using #(read-string (str "10r" %)) but of course parseLong (even parseInt) is much better and cleaner.

Alex Miller (Clojure team)19:04:51

Clojure is just going to convert it to a long anyways in most contexts

matan19:04:40

Unrelated: so sad we have no currying behavior in the language itself

matan19:04:35

I mean that we cannot curry our functions very elegantly like in other functional languages 🙂

tbaldridge20:04:46

@matan, what does currying give you that something like partial doesn't?

matan20:04:08

you are right, I just dug partial now!

tbaldridge20:04:50

it's not exactly the same, but Clojure has multi-arity functions which I find much more useful than curried functions.

matan20:04:15

now I'm confused for a moment about what's the actual difference

matan20:04:31

between what partial accomplishes v.s. currying

tbaldridge20:04:18

So here's the difference, assume we have this function: (fn add [a b] (+ a b))

tbaldridge20:04:01

the curried form would be: (fn add [a] (fn [b] (+ a b))) which you could then call like ((add 40) 2) => 42

tbaldridge20:04:17

partial application takes a function and returns a function that takes less arguments because some of them have been already applied:

(defn partial [f a]
    (fn [b]
      (f a b)))

((partial add 40) 2) ; => 42

tbaldridge20:04:01

So in a very broad sense, currying modifies the definition of a function. partial creates a new function that wraps an existing function.

mobileink20:04:15

"already applied"? (nit, sorry)

mobileink20:04:59

@matan partial application fixes but does not apply the 1st arg. currying turns a multiarity fn into a proper fn (1 arg only) without fixing the 1st arg. or: curry applies to fns without args. partial applies to fns and args. i think. neither modifies fn defn, both produce new fns.

tbaldridge20:04:29

Right, it depends on the language implementation.

tbaldridge20:04:40

But as an example, this is why I like mult-artiy functions:

(defn add
  ([] 0)
  ([x] x)
  ([x y] (+ x y)))

tbaldridge20:04:05

In a language like clojure you then get (add 42) => 42. In a language that is curried (like F#), (add 42) => <function add>

tbaldridge20:04:24

(ignoring the fact that you can't even do multi arity functions in most of these languages)

mobileink20:04:29

hmm. computing... always liked curry/uncurry. maybe just for the elegance.

mobileink20:04:53

where you say "multi-arity" i wpuld say "variable arity", on grounds that anything more than 1 arg counts as multi-arity.

mobileink20:04:34

but that's a quibble, i see the pt.

tbaldridge20:04:11

Well multi-arity is what clojure has, where you can have different logic for each number of parameters. And that doesn't even touch variadic functions which are when you have (fn [& rest] ...)

mobileink20:04:50

i guess i would say the nice thing about curry is you do not need to write one implementation per added arg.

mobileink20:04:18

so you define add for n args, and you're done. you don't need to make a bunch of defns.

mobileink20:04:08

plus, whether you think (add 42) => 42 is a good thing or not.

mobileink20:04:06

i'm inclined to think not, altho is it convenient.

tbaldridge20:04:05

taking this into a thread so we stop dominating the main chat

tbaldridge20:04:55

The problem is let's say you have (fn add [a b] ...) as a curried function. There is no way to have that function take 2 or 3 args. You have to pick what the final number of args would be.

tbaldridge20:04:34

If you give the definition 3 args, and then only use two you get back a function...what use is that?

mobileink20:04:09

what do you mean by "as a curried fn"? my understanding is you def a multi-arity fn, and you can apply curry to it. i'm prolly mussing sth. heh.

mobileink20:04:49

iow the only curried fns are the ones to which curry has been applied.

tbaldridge20:04:11

no, there are actual languages that only implement single arity functions.

tbaldridge20:04:38

All functions take one arg, if you do (defn add [a b] ...) it compiles down to (defn add [a] (fn [b] ...))

mobileink20:04:07

in which case you do not need curry, no?

mobileink20:04:28

that's essentially what functional means, afaik: one argument max. if you want more you need a mechanism like curry.

mobileink20:04:23

i could be wrong about this, but i believe it is not possible to define multi-arity fns in the lambda calc.

mobileink20:04:52

so you need additional mechanisms.

dpsutton21:04:19

i think what was missing here maybe was a more concrete example? In clojure we can of course do (+ 1 2 3 4 5 6) whereas in an ML you would have to do (1 + (2 + (3 + (4 + (5 + 6)))))

mobileink21:04:05

pretty sure ML has a curry op. what would that look like?

dpsutton21:04:09

ML is curried by default

seancorfield22:04:24

ML doesn’t have variadic functions as I recall. But ML doesn’t need parens in calls, so fun add a b = a + b defines a curried add function, such that add 1 is an increment function and add 1 2 returns 3.

seancorfield22:04:07

And the variadic function issue is what @tbaldridge alluded to above — you need to define the fixed maximum arity.

mobileink19:04:57

nutty question: any theoretical reason why we could not curry variadic fns? if we treat numbers as fns (which is not a rad concept), why not? (((curry add*) 1) 2) produces a fn, which evaluated with no args gives 3. applied to 3, it gives (a fn which...etc) gives 6.

mobileink19:04:48

seems reasonable to me, at least in principle.

mobileink20:04:12

ok, "curry a variadic fn" means "curry a fn whose one arg is a variadic tuple".

mobileink20:04:56

personally i prefer (((curry add) 42) 3) => 45. except for all those parens, ewe!

Drew Verlee23:04:38

I dont seem to grok the meaning of keywords. I see how their used, but i feel like i could just use Strings instead. I’m trying to understand this answer, but it seems to just circle the subject. https://stackoverflow.com/questions/11655080/in-clojure-why-have-strings-keywords-and-symbols

Drew Verlee23:04:02

The answer seems to be that their are ways you can use keywords where you can’t use strings. Or maybe its about being backwards compatible with how java thinks about strings?

Drew Verlee23:04:31

I suppose, specifically i dont understand this line in the answer: > Strings do not implement the required interfaces to look themselves up in maps.

noisesmith23:04:45

@drewverlee (:foo {:foo 42}) returns 42, you can only do that by having keywords implement an interface

Drew Verlee23:04:52

Yea that answers that specific question. Thanks!!! So you can’t use strings as functions. But sense you can use the map as the function to the string they don’t seem practically different in use. Or i’m i missing something?

Drew Verlee23:04:25

im trying to write a tutorial for my company and i just realized i dont have a strong grasp on this 🙂

noisesmith23:04:27

what if you are mapping lookup on a sequence of hash-maps

noisesmith23:04:43

eg. (map :foo [m n o p])

noisesmith23:04:02

(a very common pattern in my codebase)