Fork me on GitHub
#beginners
<
2018-01-21
>
david47901:01:21

that's great that you can make it work with destructuring, but the performance argument is another reason to use core.match instead, since it's quite optimized

vincent.cantin03:01:54

Hi. I am not yet clear about the difference between :name and ::name. Is ::name still considered just a normal keyword with a different name? Why people are using ::name instead of :name sometimes?

seancorfield03:01:57

@vincent.cantin the :: prefix means "auto-resolve the namespace qualifier": if you have ::name in the namespace foo.bar, then it means :foo.bar/name; if you have an alias -- (:require [foo.bar :as fb]) -- and ::fb/name than it resolve the alias to :foo.bar/name. Does that help?

vincent.cantin03:01:10

oh, yes! It totally solves the mystery. Thank you.

vincent.cantin03:01:47

Is there a difference between (.getElementById js/document "app") and (js/document.getElementById "app") (both seem to work). Which one should be preferred?

seancorfield03:01:41

The former is what I've seen in ClojureScript. I'm a little surprised that the latter works.

seancorfield03:01:24

(.method object arg1 arg2) is the normal Clojure(Script) call format for interop with the OOP host.

seancorfield04:01:32

Interesting... I expect it works by accident, as a parallel for (SomeThing/staticMethod arg1 arg2) ?

noisesmith04:01:49

I hear tell there's at least one place where it was used in a Rich Hickey commit - but there's an example mfikes showed where if you use the normal syntax it can give you a clear error message about a binding, and if you use the pseudo-interop syntax it just fails with an undefined at runtime

noisesmith04:01:59

iirc it involved shadowing without a warning

vincent.cantin04:01:54

I also found (. js/document getElementById "app") on github, which works too (I tested it).

noisesmith04:01:07

that is what (.getElementById js/document "app") expands to - it's lower level but easier to use from a macro if you are generating an interop call

igor.larcs13:01:32

Hey! Is there a way to map a collection while reducing another one arbitrarily while injecting it onto the mapped one? eg. I have a vec [1 2 3] and I want o map it while injecting in its context all the contents of [2 2 2], I want to do so that when iterating through 2 (first vec) it matches the first 2 of the second vector and removes it as to when iterating through 3 I`ll only have [2 2] as a context for 3 to work with.

ackerleytng14:01:20

i'm confused by what you need... usually if there are too many things that i need done to a vector, i'd split it into a few functions

sundarj15:01:29

@igor.larcs does this work for you?

(reduce
 (fn [result input]
   (println result input)
   (if (= 2 input)
     (rest result)
     result))
 [2 2 2]
 [1 2 3])
[2 2 2] 1
[2 2 2] 2
(2 2) 3
(2 2)

igor.larcs15:01:56

@sundarj it might! I'm gonna test it against my problem

sundarj15:01:25

let me know! 🙂

harrigan16:01:20

Hi all, a question on using deps.edn with a git library: I’ve created an empty project with just a deps.edn:

{:deps {org.clojure/data.priority-map
        #_{:mvn/version "0.0.7"}
        {:git/url "" :sha "043a45342be7fbfa6cfa6363e522fcffeb3fd7bc"}}}
With the mvn coordinate, clj works fine. But with the git coordinate, it produces:
version      = 1.9.0.297
install_dir  = /usr/lib/clojure
config_dir   = /home/martin/.clojure
config_paths = /usr/lib/clojure/deps.edn /home/martin/.clojure/deps.edn deps.edn
cache_dir    = .cpcache
cp_file      = .cpcache/2317405680.cp

Refreshing classpath
Error building classpath. nil

vincent.cantin16:01:07

Is -> being part of a function name affects its semantic? In other words, what does it do?

sundarj16:01:13

that is one of the factory functions clojure generates for you after creating a Record

sundarj16:01:27

(defrecord Person [name age])
boot.user.Person

(->Person :gary 12)
#boot.user.Person{:name :gary, :age 12}

(map->Person {:name :gary, :age 12})
#boot.user.Person{:name :gary, :age 12}

vincent.cantin16:01:29

oh, I see. So -> still has no language meaning. That explains a lot.

sundarj16:01:27

(doc ->Person)
-------------------------
boot.user/->Person
([name age])
  Positional factory function for class boot.user.Person.
nil

(doc map->Person)
-------------------------
boot.user/map->Person
([m__7585__auto__])
  Factory function for class boot.user.Person, taking a map of keywords to field values.
nil

sundarj16:01:10

glad to have helped 🙂

vincent.cantin16:01:00

I wonder why I miss that important bit of information. I may have missed the normal/standard learning trail.

sundarj16:01:28

well, if you've never seen it before, it's natural to wonder what it means 🙂

sundarj16:01:44

note that Clojure is a lot more permissive in terms of symbols in names than other languages

sundarj16:01:45

(def !?*-><%$#& 2)
#'boot.user/!?*-><%$#&
        
!?*-><%$#&        
2

harrigan16:01:32

Ah, upgrading to 1.9.0.309 fixed the above problem.

lockdown-17:01:25

What's makes a collection reducible, that it knows how to reduce itself?

sundarj17:01:47

@lockdown- read the source:

boot.user=> (source reduce)
(defn reduce
  "f should be a function of 2 arguments. If val is not supplied,
  returns the result of applying f to the first 2 items in coll, then
  applying f to that result and the 3rd item, etc. If coll contains no
  items, f must accept no arguments as well, and reduce returns the
  result of calling f with no arguments.  If coll has only 1 item, it
  is returned and f is not called.  If val is supplied, returns the
  result of applying f to val and the first item in coll, then
  applying f to that result and the 2nd item, etc. If coll contains no
  items, returns val and f is not called."
  {:added "1.0"}
  ([f coll]
     (if (instance? clojure.lang.IReduce coll)
       (.reduce ^clojure.lang.IReduce coll f)
       (clojure.core.protocols/coll-reduce coll f)))
  ([f val coll]
     (if (instance? clojure.lang.IReduceInit coll)
       (.reduce ^clojure.lang.IReduceInit coll f val)
       (clojure.core.protocols/coll-reduce coll f val))))
nil

lockdown-17:01:20

@sundarj I understand reduce

lockdown-17:01:46

but what collection can't reduce itself?

bronsa17:01:04

@lockdown- it either implements IReduce/IReduceInit or it extends CollReduce

lockdown-17:01:40

@bronsa what collection doesn't implement those interfaces?

noisesmith17:01:01

it's straightforward to find outin a repl

+user=> (supers (class []))
#{clojure.lang.IPersistentCollection clojure.lang.APersistentVector clojure.lang.IReduce clojure.lang.IFn java.lang.Comparable clojure.lang.IHashEq clojure.lang.IPersistentVector clojure.lang.IMeta java.util.List clojure.lang.Seqable clojure.lang.IObj java.util.concurrent.Callable java.util.Collection clojure.lang.IReduceInit clojure.lang.IEditableCollection clojure.lang.ILookup clojure.lang.Sequential clojure.lang.Counted clojure.lang.Indexed java.util.RandomAccess clojure.lang.IPersistentStack java.lang.Iterable clojure.lang.Associative java.io.Serializable clojure.lang.Reversible java.lang.Runnable java.lang.Object clojure.lang.AFn clojure.lang.IKVReduce}
+user=> (supers (class ()))
#{clojure.lang.IPersistentCollection clojure.lang.IHashEq clojure.lang.IMeta java.util.List clojure.lang.Seqable clojure.lang.IObj java.util.Collection clojure.lang.Sequential clojure.lang.Counted clojure.lang.IPersistentList clojure.lang.IPersistentStack java.lang.Iterable clojure.lang.ISeq java.io.Serializable java.lang.Object clojure.lang.Obj}
+user=> (contains? (supers (class [])) clojure.lang.IReduceInit)
true
+user=> (contains? (supers (class ())) clojure.lang.IReduceInit)
false

lockdown-17:01:25

why does (reduce + 0 '(1 2 3 4 5)) works then?

noisesmith17:01:56

because you can reduce things that don't implement IReduceInit

noisesmith17:01:08

IReduceInit is an optimization that reduce uses if available

noisesmith17:01:48

it lets the collection reduce itself, instead of reduce doing it

lockdown-17:01:56

so what does those interfaces actually?

noisesmith17:01:30

if you implement that interface, you implement reduce

noisesmith17:01:54

otherwise, the reduce function accesses your data as a sequence and does the reducing itself

lockdown-17:01:42

don't get it haha, for example, why range knows how to reduce itself?

lockdown-17:01:07

like reduce itself to what?

noisesmith17:01:23

it's for performance - range can reduce with your function in a way that's faster than the reduce function doing it by asking for the next item repeatedly

noisesmith17:01:04

the reduce method in IReduceInit requires an initial value and a function - so it reduces using those arguments, and should have the same result the reduce function would have

lockdown-17:01:03

I see, ok its mostly an optimization, eliminates intermediate results contrary to reduce function doing it by asking for the next item repeatedly as you said

noisesmith17:01:26

right - I'd say it's more than "mostly" an optimization - it would be possible for some version of IReduceInit forsome collection to do something reduce wouldn't do, but I don't think it would be a good idea

lockdown-17:01:23

ok, for me now, since I'm just learning, and don't care much about performance yet, a simple answer is that reduce will performance better on reducible collections than in no reducible collections

lockdown-17:01:58

@noisesmith transducer make use of this too right? transducer are also primarily an optimization ?

bronsa17:01:14

no transducers are not an optimization, they're a different abstraction

lockdown-17:01:14

@bronsa transducers avoid creating intermediate sequences by composing transformations into a single one, what are the other benefits?

bronsa17:01:05

because they compos transformations that are independent of input or output sources

bronsa17:01:44

you can use them lazily, eagerly, sequentially, in parllell, in async contexts etc

lockdown-17:01:01

yes, I mean they are an abstraction that lets you compose transformations, but what's the end goal?

drewverlee22:01:54

I think of the goal of transducers as identifying that the function can be separated from the input and output. The transducer is function that performs the transformation without knowing the input it operates over and the output collection it creates. By reducing coupling (input and output) were able to create more re-suable abstractions and more high level abstractions.

drewverlee22:01:06

Does that help?

drewverlee22:01:15

In immediate benfiet of this is that it allows a function, which is a series of transformations, to be used as a be passed as an argument.

bronsa17:01:11

they're not just an optimzation to remove intermediate sequences

lockdown-17:01:02

thought they were just used eagerly

bronsa17:01:30

user=> (take 2 (sequence (map inc) (range)))
(1 2)
this is lazy