Fork me on GitHub
#beginners
<
2020-08-23
>
Noor Afshan Fathima11:08:16

I am trying to run this code

(defn transform-all [f xs]
  (if (first xs)
    (cons (f (first xs))
          (transform-all) f (rest xs)))
  (list))

Noor Afshan Fathima11:08:31

(transform-all inc [1 2 3 4])
(transform-all keyword ["bell" "hooks"])

Noor Afshan Fathima11:08:50

It gives me

Wrong number of args (0) passed to: playground.core/transform-all

Noor Afshan Fathima11:08:02

I donโ€™t understand the issue

dakra11:08:55

(defn transform-all [f xs]
  (if (first xs)
    (cons (f (first xs))
          (transform-all) f (rest xs)))
          ^
          +--------- you call transform-all without arguments here
  (list))

Endre Bakken Stovner15:08:55

Do you have any suggestions for advanced acync tutorials? I've read through the Clojure for the brave and true chapter and the two courses on http://purelyfunctional.tv. Both are great.

Endre Bakken Stovner15:08:55

Do you have any suggestions for advanced acync tutorials? I've read through the Clojure for the brave and true chapter and the two courses on http://purelyfunctional.tv. Both are great.

MatD17:08:28

Hi! List vs Vector question why does group-by return vectors while the juxt version return lists?

(group-by odd? [1 2 67 12 33 21])
--> {true [1 67 33 21], false [2 12]}
((juxt filter remove) odd? [1 2 67 12 33 21])
--> [(1 67 33 21) (2 12)]

dpsutton17:08:17

(doc group-by) because that's group-by's intention from the doc-string

Returns a map of the elements of coll keyed by the result of
  f on each element. The value at each key will be a vector of the
  corresponding elements, in the order they appeared in coll.

dpsutton17:08:05

group-by uses a transient map with vectors as the value for accumulating. filter and remove return lazy sequences as they are quite general and can handle possibly infinite seqs. group-by on the other hand is not lazy

๐Ÿ‘ 1
Stuart17:08:57

I have a 2d vector like so:

(def example-map
  [[:o :o :o :w :o :o :o :o :o :o :o :o :o :o :o :o]
   [:o :o :o :w :g :o :o :o :o :w :o :o :o :o :o :o]
   [:o :o :w :w :w :w :w :w :w :w :w :w :w :w :o :o]
   [:o :o :w :o :o :o :o :o :o :o :o :o :o :w :o :o]
   [:o :o :w :w :w :w :w :w :o :o :o :o :o :w :o :o]
   [:o :o :o :o :o :o :o :o :o :o :s :o :o :o :o :o]
   [:o :o :o :o :o :o :o :o :o :o :o :o :o :o :o :o]])
ANd if i want to find the location of :g or :s, I'm doing this:
(defn find-in-map [map target]
  (loop [y 0
         map map]
      (let [idx (.indexOf (first map) target)]
        (if (neg? idx)
          (recur (inc y) (rest map))
          [y, idx]))))
Is their a nicer way? I just want to be able to ge thte location of an item in a 2d vector?

Stuart17:08:32

i dont have to worry about the item not being present

Stuart17:08:32

i dont have to worry about the item not being present

jsn18:08:07

(defn f [m x] (->> m (map-indexed #(vector %1 (.indexOf %2 x))) (remove (comp neg? second)) first)) well, you could do something like this

jsn18:08:19

or (defn f2 [m s] (first (for [y (range (count m)) :let [x (.indexOf (m y) s)] :when (not= -1 x)] [y x])))

Stuart18:08:23

oh thats neat! I never though of list comprehension

Stuart18:08:42

something I need to keep in mind, havent' really used languages with list comprehension before so i keep forgetting about it

blogscot11:08:46

Just for practice I came up with this solution:

(defn find-in-map [m t]
  (for [y (range (count m))
        x (range (count (first m)))
        :when (= t (get-in m [y x]))]
    [y x]))
I try to avoid calling out to Java if I can help it.

๐Ÿ‘ 1
Stuart19:08:47

sigh just been sat with a dumb problem for a while where the following worked:

(cell-summary-fn (first neighbours))
(cell-summary-fn (second neighbours))
(cell-summary-fn (last neighbours))
BUt
(map cell-summary-fn neighbours)
didn't... I had named the argument to my function map .... ๐Ÿ˜–

dpsutton20:08:51

Itโ€™s a rite of passage to learn where your comfort is with shadowing core functions. I lean towards almost never for this very treason. :)

seancorfield20:08:03

It's partly why you'll see so many one-letter, or at least very short, identifiers for generic values, such as m for a map, v for a vector, k for a key, and stuff like xs for a sequence of x things ๐Ÿ™‚

Zebra21:08:45

Hello everyone! I have a question, sorry if it is a controversial one. Mostly about types and maintanability, i just feel a bit more safe when using rust(or ocaml,elm), because compiler can pinpoint issues when, for example, i break existing callers, mismatch types and just all around do refactoring and maintaining the project,but with clojure i cant be so sure when refactoring system while it grows because i just cant hold all the invariants in my head because im just a human. So, the questions is, how do you deal with such issues in clojure (not including tests because i write them for both, and clj-kondo), especially with shared local libraries?

Lennart Buit21:08:20

I guess the idiomatic answer here would be specs, instrumentation and generative tests. So, in Rust, or maybe Haskell, you would create types for things like Point[s] and Vector3[s] etc. This is not as common in Clojure: we tend to use the same few containers in many different ways: a map with x and y? oh we can treat that as a point, an array of three values? oh we can treat that as a Vector3 This is also where spec then comes in: In clojure you tend to write functions that expect a certain shape, but are indifferent about type. Spec lets you define the shapes of your data with constructs like s/keys and s/coll-of etc. For example: A function that adds points could just be a function that takes two maps with xs and ys. Furthermore, you can define function specs with s/fdef that can be used to enforce these contracts. That usually happens in either of two ways: You can instrument functions meaning they will raise when its called with arguments it doesnโ€™t accept, or you can use generative testing to assert that each combination of inputs generates a valid output.

Lennart Buit21:08:58

With respect to shared libraries, there are libraries that also offer specs for their public API: that means that you can instrument this library and discover misuse of the library in your own code in the design by contract kinda way.

Lennart Buit22:08:45

I understand the sentiment tho: I had the same when I started Clojure: How can I be sure that a refactor doesnโ€™t break everything when there is no type checker to help me with that? I think the answer here is that Clojure programmers assign less value to strict type checking because they often write programs using a few constructs applied in many different ways. A quote you see reiterated here often: > It is better to have 100 functions operate on one data structure than 10 functions on 10 data structures. > โ€” Alan Perlis That makes that if you write programs that just use vectors, maps, sets and so on that spec is an excellent addition to gain some way to assert about the shape of data, without having to buy into the rigidity of a type system.

Lennart Buit22:08:28

(Hope this helps! Bit of an abstract answer, I guess)

seancorfield22:08:37

@U0181TUEAC8 I just wanted to +1 much of what @UDF11HLKC has said here: we tend to work with generic data structures and, where possible, generic functions -- which is a big contrast to typed languages that have specific types and specific operations. For example, we can treat all of hash maps, sets, vectors, and lists as just "sequences" and so we have a number of generic sequence functions. We can treat hash maps as "associative" (that seems obvious) but vectors are also associative (on their indices). We can treat both hash maps and sets as "lookup" types and call contains? on them.

seancorfield22:08:05

It's something you get used to over time -- and folks who prefer "types" tend to leave Clojure and go back to their typed languages -- but if you find you like Clojure's approach, you'll tend to then in much more abstract terms about operations, and you can come up with solutions that would be a lot more verbose in other languages.

seancorfield22:08:38

I've worked with a very wide variety of languages over about 35 years as a professional software developer: some strongly typed, some weakly typed, some statically typed, some dynamically typed. In the end, the language I find myself more productive in and that I enjoy working with most of all is Clojure -- and I've been doing production Clojure for a decade now. I also try to make sure I learn a new language every year or two, so I've spent time with Rust, Kotlin, Go, Elm... and I keep dabbling with Haskell (my postgraduate work in the '80s was on ML-style languages and type inference was one of the things I explored).

Zebra09:08:17

@UDF11HLKC, @U04V70XH6 thanks!

amirali21:08:36

Hi folks I got a stupid question that can't figure out really. When I use a connection channel to receive data from somewhere (using RabbitMQ-Langohr) , without putting it inside a loop, it continuously recieves data whenever data is available in handler. while when using core.async i must use a loop to !> or <! a channel continuously... How is that possible? And should i use go-loop to put connection-channel's data into my async channel? (I can't test it because server is unavailable now!) Thanks in advance!

amirali21:08:36

Hi folks I got a stupid question that can't figure out really. When I use a connection channel to receive data from somewhere (using RabbitMQ-Langohr) , without putting it inside a loop, it continuously recieves data whenever data is available in handler. while when using core.async i must use a loop to !> or <! a channel continuously... How is that possible? And should i use go-loop to put connection-channel's data into my async channel? (I can't test it because server is unavailable now!) Thanks in advance!

Zebra21:08:04

Except go-loop instead of (go (loop))

Zebra21:08:17

And when-let instead of let