This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
- # announcements (8)
- # babashka (19)
- # beginners (100)
- # boot (3)
- # calva (16)
- # cider (8)
- # cljdoc (6)
- # cljsrn (15)
- # clojure (73)
- # clojure-europe (7)
- # clojure-france (1)
- # clojure-italy (12)
- # clojure-nl (11)
- # clojure-sg (1)
- # clojure-uk (17)
- # clojurescript (63)
- # crux (3)
- # cursive (22)
- # data-science (2)
- # datomic (2)
- # defnpodcast (1)
- # docs (1)
- # fulcro (7)
- # graalvm (8)
- # jackdaw (1)
- # kaocha (11)
- # off-topic (26)
- # pedestal (4)
- # planck (1)
- # re-frame (35)
- # reitit (5)
- # ring (3)
- # shadow-cljs (25)
- # slack-help (11)
- # spacemacs (8)
- # specter (2)
- # tools-deps (61)
- # vscode (6)
I never thought of using
as-> simply to put a label, but I'm thinking about it now...
Like even if it ends up being in the same place, but as an alternative of switching to a let. Not sure if that would be a good pattern or not
(-> (process payload) (as-> customer (get-cart customer)) (as-> cart (checkout cart)
(-> (process payload) (get-cart) (checkout))
(let [customer (process payload) cart (get-cart customer)] (checkout cart))
Threading with -> looks cleanest to me. Next best is using let. Third best using as->.
but the point is taking advantage of having 1 argument only (I think this is called currying) being forwarded
as-> seems to be nice for people who are not used to it
good for welcomening people at the language tho
Currying is different, and Clojure doesn't support it, but it does support partial application which is somewhat similar.
Currying is when you can call a function with only the first argument provided, and it will return a function with the rest of the arguments.
(defn add [a b c] (+ a b c)) if you call
(add 1) it will return a function of the shape:
(defn add [b c] (+ 1 b c))
Haskell uses currying, and because it allows to call functions without parenthesis, you can do:
add 1 2 3 which in reality is 3 function calls curried together such as:
(add 3 (add 2 (add 1))).
Clojure instead has partial function application, which you can use using
partial and lets you do:
(partial add 1) which returns a function that takes the remaining args. The difference is it is explicit, you need to use
partial, and it also supports more than one arg at a time such as
(partial add 1 2) which will return a function taking only c. That said, it is more typical to use function closures for this instead and do something like
#(add 1 2 %) which similarly returns a function that only needs to take c.
The threading macros are unrelated, but I can see why you might think they are. The threading macros don't create any higher order functions though, they're just a syntax for composing functions together in a possibly more convenient or readable manner.
You're right that in general, it makes sense to use threading macros for data pipelines, where basically each function takes the same type of data, apply some transformation to it, and return it for the next one to process. And there are conventions in Clojure that if your data is a sequence, then the functions that take a sequence and return a modified sequence take the sequence as the last argument. Similarly, if instead of a sequence, the data was a collection, then the convention is for it to be the first argument. Thus
-> is used for collection processing and
->> is used for sequence processing.
My examples above though aren't like that, they show a case where the type of thing being processed changes as we move in the pipeline, that's where I feel
as-> can be valuable, since it can clearly document by giving a name to the intermediate data that the data type has changed.
thanks for explaining those concepts, especially currying that i misunderstood for partial application the situation you expplained make sense, regarding signalizing that the data type has changed but wouldn't it be better to rename the functions to reflect that instead? (supposing you control their signatures, of course)
Ya, that's an option for sure. Honestly, this is the first time I think of using
as-> that way. So I don't know if it would turn out to be a great thing that I'd stick with, or a bust. Someone on some other channel I had talked about this pointed out what you just did, that with better function names, you might not need this, say you named the function
(customer->cart), now its kind of clear that your threading a customer in, and getting a cart out. I'll probably give both a try, and see where I land.
Do you mean you want to create a Java JAR file that has resources in it, and you want a Clojure program running from that JAR to somehow scan for all file names in those resources?
Or that there is just a directory on the file system named "resources" and you want to scan through all files in it?
somehting like this
(->> "stubs" (io/resource) (io/file) (file-seq) (filter #(.isFile %)) (map read-single-file))
I have a folder with several EDN definitions for a mini-dsl I created and for now, I need to specify each file-name directly to
io/resource so I can get them loaded
beware that calling (io/file) on (io/resource) produces a not a file exception when reading from a jar.
thanks @ but I think this solution has some limitations when running inside a jar file, right?
my rule of thumb - do not relly on reading directory content from jar. Only exclusion - when I know filename and need to read that file only (configuration options for example)
resources in jar is a week abstraction. It is possible to add some external dependency that will introduce extra files in the same directory that you are reading from. That leads to unexpected behaviour in production
that's a good point, how would you approach a situation where I expect a user of my library to inform me about EDN files in his project so I can read them?
I would force user to make a list of files and pass it as an argument to your function. So responsibility of your library is to take a list of files, check if they are all available to read, read, create an error with a full path to the file if some of them can not be read or contains wrong information, and produce expected result. Espected mean documented.
Consumer of your library can get this contract from function’s documentation and will be responsible for building a list of files.
I’m not claiming this is a “right” approach. This is just a way how I would start designing my API. And I believe there are a lot of consideration to take in account to make API of your function powerful enough and at the same time easy to consume.
Be aware that changing the value of a var (i.e. mutating it) removes one of the principle benefits of Clojure, which is immutable values. Mutable vars are a major source of hard-to-detect and hard-to-fix bugs in a number of other programming languages, so it’s worth taking a long hard look at why you want to change the var, and seeing if perhaps there’s a more idiomatic approach that will serve you better.
I am passingly familiar that is the name of a file format. It isn't clear if that is what the questioner was asking about.
def does not provide any multi-threaded safety guarantees that I know of, but in an interactive development context it gets the job done pretty well.
If you want some kind of nice multi-threaded safety properties, then I am not sure if Vars provide any ways to 'safely' change them in a way that is visible across threads.
alter-var-root might be different than
def in terms of exactly what it provides. I haven't dug into it deeply to determine the precise difference.
Hello! I'm messing around with
deftype and have created the following:
As I've built this out using
(deftype ManagementApi [api] ManagementApiProtocol (get-connection [_ params] (js-invoke api "getConnection" params)))
deftypeI'm realizing that just using a regular function seems to get the job done just as well. Is there some benefit to
deftypethat I'm not seeing? Thanks!
(defn get-connection [api params] (js-invoke api "getConnection" params))
deftype can be useful if you're planning on having several implementations of a protocol which will get injected into your app according to the context. (E.g. you might have a "prod" version and one for testing locally.) But personally always my first reaction when I find myself reaching for
defrecord is to ask myself whether what I'm doing could be done easily enough with plain functions.
Clojure has a more flexible dispatch mechanism in defmulti/defmethod (double dispatch). On the other hand, the JVM, written primarily for Java, has a highly optimized dispatch on data type. It is fast but not as flexible since it cannot do double dispatch. Use deftype/defrecord if you need to avail this optimized path by creating a new Java type. Use defrecord when you are essentially representing an entity and deftype when you want lower level control e.g. creating a new collection type. Use a function if that's enough. Next try defmulti as a pure Clojure solution. If you really need it, resort to deftype/defrecord.
I haven’t done much with
deftype myself, but my understanding is that it’s mostly useful for Java interoperability. If you’re just writing straight Clojure you’re probably better of with a straight function.
If you use predominantly full-stack CLJS, does it still make sense to say you use "Clojure?" A semantics question
Depends on the context and audience. If I’m speaking to my granny I say I do computer stuff If I’m speaking to a programmer I’d say clojure. And if I’m speaking with clojurians I’d call it cljs
In the Clojure community, is using abbreviations okay? For example, I am thinking of writing a whole namespace of permissions, but everything is just using
perm instead of
permission, so I would have tokens like
(defn get-perm-list) instead of
(defn get-permission-list) . Is this a good or bad idea?
An alternative, for when you find your doing a lot of
delete-permissions is to just name the namespace something like
you.app.permissions and then just call the functions
delete etc. This means that you would expect consumers to call your ns like
Hello, how could I model in Clojure an Intermediate Represention like llvm ? or just plain ARM assembly for example
There are multiple choices there, but for example a Clojure map for each instruction, with one key :opcode and other keys :dest :source etc. for operands, which might differ from one opcode to another. A vector of those maps for a sequence of instructions would be reasonable for many purposes, I would guess.
I am sure I have seen some Clojure projects that manipulate assembly-level code for some kind of processor before -- not sure if I remember how to find them.
well it's not for an emulator, just to make somekind of assembler using Clojure as a DSL
I have not examined the code of any of them to see how well documented or explained any of them are.
I mainly thought to look that up because at least some of those projects might represent the target machine code in Clojure data, but I haven't checked to see if any of them do.
Here is one that provides a functional interface to JVM byte code generation: https://github.com/jgpc42/insn
Not sure if https://github.com/nasser/symba is the kind of thing you're talking about or not, but there are some great ideas in there and the related projects as well
yeah I saw his talk about MAGE and MAGIC which was really awesome, took but when I looked at the code, it was just taken from C# namespace which then didn't help me really in my task ^^'
Here's a sample of the representation in my toy x86 assembler: https://github.com/nathell/lithium/blob/master/examples/stripes.li.clj
hi everybody, i'm looking for a clojurescript resource for beginners to web development. does anything like that exist? i didn't find anything in the link in the topic.
i feel silly asking this because i thought finding such a resource would be easy, so now i feel like i missed something obvious
This channel is focused primarily on beginners, but might not have as many experienced clojurescript devs looking to answer questions as the #clojurescript channel does.
Is anyone using Visual Studio Code? I am wondering if anyone knows the command to move a something INSIDE a () so for example I have:
and I want to do
I start with putting my brackets before
() @test but I see in a lot of videos that you can simply push the () into it...
I'm sorry for my english and maybe bad explanation.
FYI, there is a #vscode channel on this Slack that may have more participants who know
Sounds like paredit "slurp" which may be bundled with Calva? (there's a #calva-dev channel as well, for Calva users)
There's more! Check out https://calva.readthedocs.io/en/latest/paredit.html Structural editing is really handy way to write clojure code
Not sure if this counts, but I just figured out that you can highlight the thing, grab it with your mouse cursor, and drop it inside of the parens. 😁
One of the nice things about paredit is that you can do so much from the keyboard -- selecting s-exprs, moving them around, merging them, splitting them.
Changing the subject a bit, have you seen the videos of devs who can drive their entire IDE/editing experience just using their voice?