This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2021-09-15
Channels
- # announcements (51)
- # beginners (65)
- # calva (44)
- # cider (6)
- # clara (3)
- # clj-kondo (30)
- # cljsrn (5)
- # clojure (63)
- # clojure-australia (7)
- # clojure-dev (7)
- # clojure-europe (43)
- # clojure-gamedev (1)
- # clojure-nl (6)
- # clojure-uk (7)
- # clojurescript (51)
- # conjure (1)
- # cursive (9)
- # datascript (16)
- # datomic (14)
- # depstar (20)
- # events (1)
- # exercism (17)
- # figwheel-main (6)
- # fulcro (9)
- # graphql (3)
- # gratitude (2)
- # honeysql (4)
- # jobs (7)
- # leiningen (3)
- # lsp (107)
- # meander (7)
- # minecraft (3)
- # off-topic (16)
- # other-languages (4)
- # pathom (4)
- # pedestal (26)
- # practicalli (4)
- # re-frame (3)
- # reitit (7)
- # remote-jobs (1)
- # shadow-cljs (26)
- # tools-deps (67)
- # vim (19)
- # vscode (1)
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
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
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”
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.
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
The user of the library will decide it, based on his requirement of which fields he needs to have populated in the sales order
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
tons of fields with lots of nils is A-OK ✅
@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 😄
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 ^_^
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))
I was going to return nil and then I thought he clojure way is to use booleans. I guess I was wrong?
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.
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?
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.
https://clojure.org/reference/transducers#_terminology here you can find a description of transducer including it’s signature
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
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
so in the above screen shpt transducer is invoked by (transduce xform f coll)
am I right?
yes, there are few functions that can invoke transducers: https://clojure.org/reference/transducers#_using_transducers
transduce
, eduction
, into
and sequence
comp
doesn’t “call” anything. It is combining several function into one.
> technically, `comp` is a valid transducer, but that is purely accidental 🙂 yeah )
same as identity
)
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 writedoesn’t look like working code
I removed some part, but wanted to understand about last 3 lines, that is as it is in code
<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
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)
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
But again, the return value of async/reduce
is another channel. To get that final value out, we read from the channel using async/<!!
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
A common point of confusion is that async
functions don't return the values, but channels that will contain the values
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 )
yes, thanks for noticing )
(proxy [Class.Subclass] ...) ; how do I correctly qualify a subclass (subclasses are nested classes in java right?)
try this (proxy [Class$Subclass] … )
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)))
You can use Clojure's format
to get a string in the desired format.
(format "%.2f" (double (/ 47 13)))
;; => "3.62"
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))))))
Thank you, @U024X3V2YN4 and @U3L6TFEJF. That solved it! Awesome. 😁
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?
> 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!
)
Here's my take on explaining this: https://www.reddit.com/r/Clojure/comments/g5ysyn/code_as_data_beginner_oriented/
and we can manipulate Clojure code in the same way the clojure data:
(resolve (first '(+ 1 2)))
gives the '+ function back@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*
.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
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
> 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!
)