Fork me on GitHub
#beginners
<
2016-02-27
>
eggsyntax02:02:22

Given '(f1 f2 f3) and '(1 2 3), how can I get ((f1 1) (f2 2) (f3 3))? ie I want to call the 1st fn on the 1st arg, the 2nd fn on the 2nd arg, etc. I feel like I'm spacing out on some really obvious core fn here.

mikeb02:02:16

On my phone and cant test but how about (map #(%1 %2) '(f1 f2 f3) '(1 2 3))

eggsyntax02:02:03

Yeah, that works. Thanks! Still, it seems like there ought to be a one-worder there, eg (juxtmap '(f1 f2 f3) '(1 2 3))...

mostr13:02:52

@mikeb @eggsyntax, weird, I tried this with (map #(%1 %2) '(dec inc inc) '(1 2 3)) and getting (nil nil nil) as a result. Any ideas why? And why I’m not getting (0 3 4)?

alexmiller13:02:08

Try [dec inc inc]

alexmiller13:02:42

By quoting you're getting symbols not functions

alexmiller14:02:20

So then you get ('dec 1) - when invoked symbols look themselves up in their value. For non maps, will return nil.

mostr14:02:52

Ahh so the result of map contains quoted symbols too...

mfikes15:02:41

@mostr: in that case the result of map is a sequence, where each item is the application of a symbol to a number, which is nil, so you get a sequence of nils

eggsyntax15:02:19

Yeah, I wasn’t happy with how I phrased that above. I wanted to say “given that I have a list of functions f1, f2, f3…” Writing it as “given (f1 f2 f3)” suggested that I was calling f1 with f2 and f3 as args. And “given '(f1 f2 f3)" causes the confusion that just happened. Maybe I could have done it with syntax-quote and unquote, but that seems unnecessarily cryptic. “Given [f1 f2 f3]” is misleading because it wasn’t a vector, it was a list. I was a bit stumped. [Tangential Q: is there a way to represent a literal backquote without the space in Slack?]

eggsyntax15:02:59

I probably should have just spelled it out as “given that I have a list of functions f1, f2, f3…”

noisesmith15:02:50

eggsyntax: usually there's no reason to care that something is a list not a vector. Unless your question is about doing associative actions or laziness, the difference is typically irrelevant

eggsyntax15:02:26

@noisesmith: fair enough, especially given that the closest core fn analogy, map, is equally happy w/ vector args.

mfikes15:02:27

@eggsyntax: one generalization of your question I find interesting is binary functions

(map apply [* + -]
 (map list [1 2 3] [4 5 6]))

noisesmith15:02:08

eggsyntax: and this fact (that map works with vectors) is not accidental or coincidential, it's part of clojure's protocol first design, and that design is why, until you do things in the ILookup interface, or expect the behavior of LazySeq, the difference between vector and list just will not matter

noisesmith15:02:36

(with few very obscure exceptions I guess)

eggsyntax15:02:58

@mfikes: wow, interesting. I tried some stuff with apply, but hadn't thought of mapping the args into lists.

eggsyntax15:02:07

Thanks, y'all simple_smile

mfikes15:02:25

I think I learned that trick from @noisesmith IIRC

mfikes15:02:17

Your intuition is you want to map apply :)

danlucraft15:02:22

Is there a cljs fiddle or bin website running anywhere? http://Cljsfiddle.net seems to be a circuit simulator now

mfikes15:02:23

I suppose you want something that makes links…

danlucraft15:02:29

@mkfines thanks, but I was hoping for more the bin kind of thing (neglected to pack my laptop so trying to practice on my iPad... 😐)

mfikes15:02:03

@danlucraft: try Replete on your iPad

danlucraft15:02:44

Ok I will, thanks!

danlucraft16:02:41

Got it, cheers.

danlucraft16:02:11

Someone should resurrect cljsfiddle though :)

mariogintili16:02:21

how would you peeps re-write this expression

mariogintili16:02:25

(= "Rich Hickey aka The Clojurer aka Go Time aka Macro Killah"
     (let [[first-name last-name & aliases]
           (list "Rich" "Hickey" "The Clojurer" "Go Time" "Macro Killah")]
       (clojure.string/join
        " aka " [ (clojure.string/join " " [first-name last-name]) (clojure.string/join " aka "aliases)]))

mariogintili16:02:39

the last 2 lines 😞

noisesmith16:02:01

well (clojure.string/join " " [first-name last-name]) is better as (str first-name " " last-name)

mariogintili16:02:17

well, isn’t that what I’m doing?

mariogintili16:02:37

> (clojure.string/join " " [first-name last-name]) ?

mariogintili16:02:50

oh wait misread your comment

mariogintili16:02:52

thought of that

mariogintili16:02:09

is there string interpolation in clojure?

noisesmith16:02:46

yes, clojure.core/format and clojure.pprint/cl-format

noisesmith16:02:24

there's probably some dark magic you can pull off with cl-format (it's mostly compatible with common lisp format)

potetm16:02:16

I would do:

(let [[fname lname & aliases] ["Rich" "Hickey" 
                               "The Clojurer" 
                               "Go Time" 
                               "Macro Killah"]]
  (str fname " " lname " aka "
       (str/join " aka " aliases)))

potetm16:02:47

I think it captures the logic fine without adding any intermediary structures or adding dynamic string interpolation.

mariogintili17:02:01

:+1: @potetm more or less what I was after

mariogintili17:02:19

but can’t see that as a massive improvement over what I first wrote

mariogintili17:02:38

I think @noisesmith format would be handy next time

potetm17:02:06

Yeah it’s marginal at best. Not actually worth a ton of time improving. format is handy, though not as much when you have a dynamic number of args.

potetm17:02:32

I can say, as an experienced clojure programmer, adding extra data structures and manipulations can cloud your intent.

potetm17:02:43

The more I can assemble with my eyes, and the less I have to assemble in my brain, the better.

noisesmith17:02:41

potetm: cl-format actually does smart expansion of lists and other such craziness

potetm17:02:07

Yeah I’ve never used cl-format before, so can’t speak to it.

noisesmith17:02:22

=> (clojure.pprint/cl-format nil "~{~a~^ aka ~}" [(str "Rich" " " "Hickey") "The Clojurer" "Go Time" "Macro Killah"])
"Rich Hickey aka The Clojurer aka Go Time aka Macro Killah"

noisesmith17:02:39

I always have to go look it up.

noisesmith17:02:41

but it does it

mariogintili17:02:10

@potetm: definetly agree with your last sentence

mariogintili17:02:16

I’m just finishing up the koans

mariogintili17:02:39

5 files to go I believe

potetm17:02:58

@noisesmith: OR (clojure.pprint/cl-format nil "~a ~a ~{~a~^ aka ~}" "Rich" "Hickey" ["The Clojurer" "Go Time" "Macro Killah”])

potetm17:02:16

That’s pretty baller.

potetm17:02:49

Gonna have to file that one away. Much appreciated simple_smile

noisesmith17:02:11

there's lots on the web about common lisp format tricks, they should just work with cl-format usually

noisesmith17:02:03

for parity with the original and all

(let [[fname lname & aliases] ["Rich" "Hickey" 
                               "The Clojurer" 
                               "Go Time" 
                               "Macro Killah"]]
  (clojure.pprint/cl-format nil "~a ~a ~{~a~^ aka ~}" fname lname aliases))

mostr17:02:22

so @mfikes @eggsyntax I’m still playing with this one https://clojurians.slack.com/archives/beginners/p1456579132001031 and eval-ing first arg works fine (map #((eval %1) %2) '(dec inc inc) '(1 2 3)). Is there any other way than using eval to make it working?

noisesmith17:02:37

mostr: any particular reason to use '(dec inc inc) (symbols in a list) instead of [dec inc inc] (functions in a vector)?

noisesmith17:02:04

mostr: ('any-symbol x y) will return nil for most x and y

noisesmith17:02:17

symbols are not the same as the values they could resolve to

mostr17:02:23

not sure, just playing with quiestion asked by @eggsyntax to learn some stuff

mostr17:02:47

sure, with vector it works fine

mostr17:02:05

so I guess in real-life this should be like you say

noisesmith17:02:10

('any-symbol x y z) will most always return z

noisesmith17:02:42

mostr: the trick here is that '(x y z) is a list of symbols, quoted so they are not resolved, so you get the symbols themselves

mostr17:02:44

yep, cause this is notFound value for get

noisesmith17:02:31

of course you could also use (list dec inc inc) but here [] is just better

mostr17:02:04

but wouldn’t list here do the same as simple quote `?

mostr17:02:26

I thought using list vs quote was just a matter of quoting-depth

noisesmith17:02:38

list doesn't quote things

mostr17:02:05

aaaah, ok, it just doesn’t evaluates this given list facepalm

noisesmith17:02:27

well, the list function gets evaluated

noisesmith17:02:43

and its args are each individually evaluated - getting the function from the symbol

noisesmith17:02:56

but it has to stop at resolving the function - no calls to resolve

noisesmith17:02:00

substitution model!

mostr17:02:17

it’s getting clear, thanks @noisesmith

noisesmith17:02:28

np, glad I could help

mfikes19:02:47

@mostr: Since you are considering evaluation with respect to symbols and functions, pondering this one might be instructive: (map #(%1 %2) [#'dec #'inc #'inc] [1 2 3])

mfikes19:02:02

This is also a good one:

(def v #’inc)
(v 0)
(#'v 0)

noisesmith19:02:26

@mfikes: wow, I never thought to check how deep the var resolution would go

mfikes19:02:48

@noisesmith: Turtles of vars and symbols down until you hit a concrete fn simple_smile

noisesmith19:02:39

it makes me sad slack does not let me add a turtle reaction to the turtle reaction itself

mfikes19:02:43

@noisesmith: One very interesting thing to me was the concept of a function value evaluating to itself, which makes complete sense, but which never occurred in regular ClojureScript. I encountered it when adding eval to Planck. Bottom half of this post if interested in the twist: http://blog.fikesfarm.com/posts/2016-01-22-clojurescript-eval.html

noisesmith19:02:20

oh - one could theoretically make a non-terminating loop using a var that resolved to itself

noisesmith19:02:33

or a stack overflow or something

noisesmith19:02:01

user=> (declare turtle)
#'user/turtle
user=> (intern 'user 'turtle #'turtle)
#'user/turtle
user=> (turtle)

StackOverflowError   clojure.lang.Var.invoke (Var.java:375)

mfikes19:02:26

(def v #’v) (v)

noisesmith19:02:38

oh, it lets you do that, much easier

mfikes19:02:29

Love this stuff. Very cool. @@@@@@@@@@@@@@@@@@@@v

mostr19:02:54

Omg, crazy stuff 😱

mfikes20:02:05

Var indirection can actually be useful:

cljs.user=> (def f inc)
#'cljs.user/f
cljs.user=> (def fs {:f #'f})
#'cljs.user/fs
cljs.user=> ((:f fs) 1)
2
cljs.user=> (def f dec)
#'cljs.user/f
cljs.user=> ((:f fs) 1)
0
If instead the symbol were used—`(def fs {:f f})`—the map value would be the function value at the time the map was evaluated.

eggsyntax23:02:29

@mostr: just saw this, I've been afk all day. Yeah, I'd just go with the vector. In the context of the original question, I had a list of fns being returned by something else, but if I were specifying them by hand I definitely would have gone with square brackets. Boy, that turned into lots of really interesting discussion simple_smile