Fork me on GitHub
#beginners
<
2021-09-15
>
popeye07:09:12

I was going through https://clojure.org/reference/transducers , and found The following functions produce a transducer when the input collection is omitted: map cat mapcat filter remove take take-while take-nth drop drop-while replace partition-by partition-all keep keep-indexed map-indexed distinct interpose dedupe random-sample , why do we need to transduce

Colben07:09:14

Hi, I am interested in learning Clojure for the last year, it is going quite slowly, because the clojure's mindset is quite different from imperative programming and there are so many new concepts to learn. I am trying to write a program similar to another of my programs written in Java-like language which is creating some sales order. This sales order has lot of possible fields to be populated from which I am usually using at most 10%. But at the same time I want to retain some "template" where all the available fields would be. My first idea was to have a map, but with map I need to define value of the keyword, which would be a lot of nils. My other idea was be to have a set with all available keywords from which I would derive a map with keywords I would like to use for certain process. Also maybe defrecord could be used. I am not sure. How would you do this? And what would be the elegant way how to create a map from this structure just with the keywords I would be using? Thanks

dgb2308:09:31

So I think you might have a struggle related to a philosophical shift here. You seem to have assumptions about how your data structure should look like based on previous experiences with other languages that use structs/classes/SQL records as their primary compositional structure. The best explanation you can get about this is in the talk “The Value of Values” by Rich Hickey. This is where I think he introduced the term Place Oriented Programming or PLOP. --- So in specific terms you simply (!) don’t put keys into map that are not there for a given instance. Later when you get handed a map that may or may not have some keys in it, you use some way of branching (you have a lot of options here) and go from there. If you want to retrieve a value from a map that is not there it will evaluate to nil which is a falsy value. So putting a value into a map that holds nil makes little sense. Aside: Your use-case sounds like you’d want to use namespaced keywords. They give you a sense of global meaning across your application. Aside 2: There are libraries like spec, plumatic/schema and metosin/malli that provide a way to describe, test, validate the shape of your data. They have a notion of “keys in a map that may be in there and how they are used”

dgb2308:09:54

In any case my advice would be: focus more on the functions that operate on your data rather than putting the shape somewhere upfront (like you would do in Java). You can still start with defining some examples so you have a clearer picture in your mind (in a comment block). I personally often do this in cases like you described.

Colben17:09:27

Thank you for your answers. I will go through the video you recommended and think abbout all you said, but still I have some question. Maybe I was not clear in my first text, my program is more like a library. A library which is making the process of creating sales order easier. And I need to have somehow defined "the list of all fields which are available" and the user of the library needs to have some way to see all the possible fields and in ideal situation to create from that definition some map which would be the subset of those fields if that makes sense. Is there some facility for this in clojure? Thanks again

dgb2320:09:38

How is decided which subset is used?

Colben20:09:14

The user of the library will decide it, based on his requirement of which fields he needs to have populated in the sales order

Colben11:09:44

for the time being i will implement this structure as a record. maybe with more experience I will have other insights. thanks again for trying to help

sova-soars-the-sora14:09:17

tons of fields with lots of nils is A-OK

dgb2314:09:39

@U3ES97LAC that really depends on what you’re doing with it and what you’re expecting it to do. My instict is that there is some fundamental confusion. But maybe I’m just confused 😄

sova-soars-the-sora03:09:03

Yeah it does depend! I was just trying to answer the OP -- he's got a bunch of HTML forms and wants to be able to fill but a subset of them. I think it's A-OK to have lots of nils or "" empty strings as the values of your fields. It's kinda best to enumerate all the keys to a map when you start developing because once the maps are persisted to storage it becomes not-so-fun to add keys later ^_^

👍 2
Benjamin07:09:01

is there a better way to say this:

(try
  (sh/sh "foo")
  (catch
      Exception e
      false))

Maravedis07:09:49

What is wrong with this one ?

Johan Thorén07:09:08

If you really need to return false, then it looks good. Except I tend to keep the catch clause on one line. If you are satisfied with returning nil, then you can just do:

(try
  (sh/sh "foo")
  (catch Exception e))

catjam 2
Benjamin11:09:48

I was going to return nil and then I thought he clojure way is to use booleans. I guess I was wrong?

Johan Thorén12:09:44

I'm still relatively new to Clojure (a couple of years as a hobbyist), but I think that it's fine to return nil instead of forcing false.

Johan Thorén12:09:13

Look up nil punning.

👍 2
Basile08:09:38

Hey everyone, it seems like I’ve got an nREPL issue. This shadow-cljs project I’m working on is starting fine and I can get Calva to both connect or jack-in. From there, I can eval in line or print to the REPL window. In emacs with cider, however, there’s no eval happening. Would that be something that rings a bell?

flowthing08:09:08

Someone over at #cider might be able to help you.

🙌 2
popeye08:09:37

is comp is transducer ?

delaguardo08:09:30

no, comp returns a function which is a composition of functions given as arguments. So if they are transducers its composition also will be transducer.

delaguardo08:09:30

https://clojure.org/reference/transducers#_terminology here you can find a description of transducer including it’s signature

popeye08:09:17

as per https://clojure.org/reference/transducers I see that

The following functions produce a transducer when the input collection is omitted: map cat mapcat filter remove take take-while take-nth drop drop-while replace partition-by partition-all keep keep-indexed map-indexed distinct interpose dedupe random-sample

popeye08:09:42

what is the meaning of input collection is omitted ?

delaguardo08:09:12

look at arities available for map function as an example: https://clojuredocs.org/clojure.core/map (map f) is an example when collection is omitted

popeye08:09:21

so in the above screen shpt transducer is invoked by (transduce xform f coll) am I right?

popeye08:09:19

which call left-to-right with a final call wher as comp calls right to left

delaguardo08:09:02

yes, there are few functions that can invoke transducers: https://clojure.org/reference/transducers#_using_transducers transduce, eduction, into and sequence

leonoel08:09:44

technically, comp is a valid transducer, but that is purely accidental 🙂

delaguardo08:09:46

comp doesn’t “call” anything. It is combining several function into one.

delaguardo08:09:24

> technically, `comp` is a valid transducer, but that is purely accidental 🙂 yeah )

delaguardo08:09:13

same as identity )

popeye09:09:57

that helped @U04V4KLKC thanks

thumbsup_all 2
popeye12:09:54

I am, trying to understand core.sync and found below code

(defn practice-async [args]
  (map fn [adata]
       (async/thread
         (
           ;;  transformation
           )))
  (async/merge)
  (async/reduce conj [])
  (async/<!!)
  )
I got that async/thread used to create separate thread for each value in the collection (async/reduce) - used to apply conj operation on result, What is the use of (async/merge) here? any way we are doing same operation using (async/reduce conj []) what is the use of (async/<!!) here? as this function helps to write

delaguardo12:09:22

doesn’t look like working code

popeye12:09:44

I removed some part, but wanted to understand about last 3 lines, that is as it is in code

delaguardo12:09:02

<https://clojuredocs.org/clojure.core.async/%3C!!%7C<!!> is taking exactly one argument which is missing in your snippet also you could check the documentation to understand what it is doing https://www.braveclojure.com/core-async/ this link is also helpful

popeye12:09:27

it was using threading macro ->> I apologise not adding it!

Fredrik12:09:32

The point of async/merge is to merge many channels into one. The map in your code will return a sequence of channels (as the return value of async/thread is a channel that will contain the return value of whatever is in the body)

Fredrik12:09:39

These channels will then be merged. The result is now a channel containing all the values from the async/thread s. To put these values into a single collection, we use async/reduce

Fredrik12:09:15

But again, the return value of async/reduce is another channel. To get that final value out, we read from the channel using async/<!!

Fredrik12:09:48

The difference between async/merge and async/reduce is that async/merge merges many channels into one channel, while async/reduce merges many values into one value

Fredrik13:09:15

A common point of confusion is that async functions don't return the values, but channels that will contain the values

popeye13:09:54

to get the value from chanel we need <!! right?

Fredrik13:09:59

Yes, exactly

delaguardo13:09:11

remeber that <!! is blocking operation so you can’t use it inside of go and go-loop blocks. This is extremely important because common suggestion for core.async is to avoid blocking at all cost )

Fredrik13:09:04

Do you mean go-loop , not go-async ?

delaguardo13:09:50

yes, thanks for noticing )

Benjamin13:09:57

(proxy [Class.Subclass] ...) ; how do I correctly qualify a subclass (subclasses are nested classes in java right?) 

delaguardo14:09:19

try this (proxy [Class$Subclass] … )

Benjamin14:09:53

yea doing package.Class$Subclass worked

jaco erasmus15:09:16

This is really basic, but it is the first program I've written/hacked from other things. But it works and it feels good! It's just a simple thing to compute percentages, because I'm too lazy to do it manually. However, I have two problems, and I'm hoping someone can help me out. First, I can't seem to figure out how to have the output print in decimal. I've been trying to use BigDecimal, but couldn't get that to work (maybe I should have shuffled parens around). Second, is there a way to quit the loop which is not typing a letter instead of a number? Here's the code:

(defn convert [total]
  (loop []
    (println "Your boring, old number is ...?")
    (let [number (Integer/parseInt (read-line))]
      (println number)
      (println "Your shiny, new number is ...")
      (* 100 (/ number total)))
    (recur)))

Fredrik16:09:52

You can use Clojure's format to get a string in the desired format.

(format "%.2f" (double (/ 47 13))) 
;; => "3.62"

schmee16:09:55

hey jaco! 1. move the computation into the println and convert it to a double:

(println "Your shiny, new number is ..." (* 100 (double (/ number total)))))
try without double also to see the difference :thumbsup: 2 check for a special exit value at the top of the loop, for example:
(defn convert [total]
  (loop []
    (println "Your boring, old number is ...?")
    (let [v (read-line)]
      (if (= v "exit")
        (println "exiting")
        (do
          (let [number (Integer/parseInt v)]
            (println number)
            (println "Your shiny, new number is ..." (* 100 (double (/ number total)))))
          (recur))))))

jaco erasmus16:09:21

Thank you, @U024X3V2YN4 and @U3L6TFEJF. That solved it! Awesome. 😁

popeye16:09:42

I came from the object oriented programming , I have basic question of clojure, What is the meaning of code is data Does that mean whatever code we write , does clojure convert as data structure and we say that is a code as data?

adityaathalye19:09:59

> What is the meaning of `code is data` One way to illustrate that idea is as follows (ref: https://github.com/inclojure-org/clojure-by-example/blob/master/src/clojure_by_example/ex00_introduction.clj#L203):

;; Why is Clojure a Lisp ("LISt Processing") language?

'(+ 1 2) ; Recall: this is a Clojure list, that Clojure evaluates as literal data.

(+ 1 2) ; if we remove the single quote, Clojure treats the same list as an executable list, 
        ; and tries to evaluate it as code.

;; More generally, Clojure code is written in terms of Clojure's own data structures. 
;; For example, here is a function definition.
(defn hie
  [person message]
  (str "Hie, " person " : " message))

;; What does it look like?
;; - Let's flatten it into one line for illustrative purposes:

;;[1] [2] [3]              [4]
(defn hie [person message] (str "Hie, " person " : " message)) ; [5]

(comment
  ;; Here:
  ;; - [1] `defn` is a Clojure built-in primitive
  ;;   - Notice, it's at the 1st position, and
  ;;   - 2-4 are all arguments to defn
  ;; Further:
  ;; - [2] is a Clojure symbol, `hie`, which will name the function
  ;; - [3] is a Clojure vector of two named arguments
  ;; - [4] is a Clojure s-expression, and is treated as the body of
  ;;       the function definition
  ;; - [5] the whole thing itself is a Clojure s-expression!
  )

👍 2
Carsten Behring08:09:51

and we can manipulate Clojure code in the same way the clojure data:

(resolve (first '(+ 1 2))) 
gives the '+ function back

jaihindhreddy09:09:12

@U7CAHM72M To be a bit pedantic, that snippet returns the var which contains the function that adds stuff. #'clojure.core/+ is the var, and to get the function out of that, we need to deref it: (deref #'clojure.core/+) This is what's happening, in-detail: The code:

(resolve (first '(+ 1 2))) 
is "read" (the R in REPL) into this data structure:
(resolve (first (quote (+ 1 2))))
And when this is evaluated, because resolve is a function, it's argument i.e, (first (quote (+ 1 2))) is evaluated and then resolve is called with the output of that. And in evaluating this, because first is also a function, (quote (+ 1 2)) is evaluated and then first is called with the output of that. Because quote is a special form and not a function, the data structure (+ 1 2), which is a list containing 3 things (a symbol and a couple of integers), is directly given to quote without evaluation. And quote's evaluation semantics are "return the thing", so (quote (+ 1 2)) evaluates to the list (+ 1 2). This is a list, and the first thing in this list, is the symbol +. This is then passed to resolve. So, the entire piece of code is equivalent to (resolve '+). And resolve returns the var/Class a symbol points to in the current namespace, as indicated by the dynamic variable clojure.core/*ns*.

dpsutton17:09:32

basically yes. you can write macros which take in code and return code. The good thing about this is that its not some arbitrary ast that maps to source code, it is literally the forms after going through the reader. (+ 1 2) is clojure code, and in a macro it is literally just a list whose first element is the symbol +, and the next two elements are 1 and 2. You can manipulate this list of items as you like and return code

🙌 2
dpsutton17:09:20

you don't have to deal with an ast like "binding nodes" and machine representations of the source code, you just deal with lists and vectors of symbols

adityaathalye19:09:59

> What is the meaning of `code is data` One way to illustrate that idea is as follows (ref: https://github.com/inclojure-org/clojure-by-example/blob/master/src/clojure_by_example/ex00_introduction.clj#L203):

;; Why is Clojure a Lisp ("LISt Processing") language?

'(+ 1 2) ; Recall: this is a Clojure list, that Clojure evaluates as literal data.

(+ 1 2) ; if we remove the single quote, Clojure treats the same list as an executable list, 
        ; and tries to evaluate it as code.

;; More generally, Clojure code is written in terms of Clojure's own data structures. 
;; For example, here is a function definition.
(defn hie
  [person message]
  (str "Hie, " person " : " message))

;; What does it look like?
;; - Let's flatten it into one line for illustrative purposes:

;;[1] [2] [3]              [4]
(defn hie [person message] (str "Hie, " person " : " message)) ; [5]

(comment
  ;; Here:
  ;; - [1] `defn` is a Clojure built-in primitive
  ;;   - Notice, it's at the 1st position, and
  ;;   - 2-4 are all arguments to defn
  ;; Further:
  ;; - [2] is a Clojure symbol, `hie`, which will name the function
  ;; - [3] is a Clojure vector of two named arguments
  ;; - [4] is a Clojure s-expression, and is treated as the body of
  ;;       the function definition
  ;; - [5] the whole thing itself is a Clojure s-expression!
  )

👍 2