Fork me on GitHub
#beginners
<
2020-01-20
>
didibus00:01:38

I never thought of using as-> simply to put a label, but I'm thinking about it now...

didibus00:01:51

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

didibus00:01:43

(-> (process payload)
    (as-> customer (get-cart customer))
    (as-> cart (checkout cart)
vs
(-> (process payload)
    (get-cart)
    (checkout))
vs
(let [customer (process payload)
      cart (get-cart customer)]
  (checkout cart))

Matti Uusitalo04:01:43

Threading with -> looks cleanest to me. Next best is using let. Third best using as->.

Marcos Silva08:01:56

but the point is taking advantage of having 1 argument only (I think this is called currying) being forwarded so as-> seems to be nice for people who are not used to it good for welcomening people at the language tho

didibus03:01:28

Currying is different, and Clojure doesn't support it, but it does support partial application which is somewhat similar.

didibus03:01:21

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.

didibus04:01:46

Something like: (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))

didibus04:01:24

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))).

didibus04:01:05

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.

didibus04:01:40

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.

didibus04:01:28

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.

didibus04:01:41

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.

Marcos Silva08:01:54

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)

didibus07:01:58

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.

👏 4
Marcos Silva13:01:04

niiiice let us know about your finds =D

didibus00:01:23

I kind of like it I feel. Reminds me of SQL 😄

bartuka11:01:35

how can I read all the files inside a folder in resources?

andy.fingerhut11:01:42

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?

andy.fingerhut11:01:49

Or that there is just a directory on the file system named "resources" and you want to scan through all files in it?

delaguardo11:01:06

(->> "stubs"
     (io/resource)
     (io/file)
     (file-seq)
     (filter #(.isFile %))
     (map read-single-file))
somehting like this

bartuka11:01:14

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

lispyclouds11:01:02

beware that calling (io/file) on (io/resource) produces a not a file exception when reading from a jar.

bartuka11:01:12

thanks @U04V4KLKC but I think this solution has some limitations when running inside a jar file, right?

bartuka11:01:32

@U7ERLH6JX thanks for pointing out this library, I will take a look at it.

delaguardo11:01:45

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)

delaguardo11:01:08

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

bartuka11:01:06

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?

delaguardo11:01:20

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.

delaguardo11:01:29

Consumer of your library can get this contract from function’s documentation and will be responsible for building a list of files.

bartuka11:01:22

uhmmm.. this is good.

delaguardo12:01:29

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.

bartuka12:01:59

yeah, sure! Thanks for your thoughts on this

Hi11:01:35

How to amend var in a namespace. I mean pemanently change for every thread

manutter5112:01:24

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.

4
✔️ 4
andy.fingerhut11:01:21

What is 'war' in this context? A WAR file?

Hi11:01:48

Sorry, I meant var

andy.fingerhut11:01:58

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.

andy.fingerhut11:01:04

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.

andy.fingerhut11:01:30

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.

andy.fingerhut11:01:04

What problem are you trying to solve?

djanus11:01:09

Also see alter-var-root .

4
andy.fingerhut11:01:51

Hmmm, yes 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.

dehli12:01:22

Hello! I'm messing around with deftype and have created the following:

(deftype ManagementApi [api]
  ManagementApiProtocol
  (get-connection [_ params]
    (js-invoke api "getConnection" params)))
As I've built this out using deftype I'm realizing that just using a regular function seems to get the job done just as well. Is there some benefit to deftype that I'm not seeing? Thanks!
(defn get-connection [api params]
  (js-invoke api "getConnection" params))

kelveden13:01:36

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 deftype or defrecord is to ask myself whether what I'm doing could be done easily enough with plain functions.

hindol14:01:39

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.

manutter5113:01:13

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.

dehli13:01:43

Thanks, that makes sense. I'll switch to regular functions then!

Kamuela14:01:15

If you use predominantly full-stack CLJS, does it still make sense to say you use "Clojure?" A semantics question

flefik14:01:04

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

clj 8
Kamuela15:01:47

Makes complete sense to me

athomasoriginal19:01:48

In a word, yes 🙂

Raymond Ko18:01:24

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 admin-perm and (defn get-perm-list) instead of (defn get-permission-list) . Is this a good or bad idea?

athomasoriginal19:01:37

As long as your consistent, it should be fine :thumbsup:

athomasoriginal19:01:45

An alternative, for when you find your doing a lot of get-permissions or delete-permissions is to just name the namespace something like you.app.permissions and then just call the functions get delete etc. This means that you would expect consumers to call your ns like permissions/get and permissions/delete

athomasoriginal19:01:18

So the alias, permissions , provides the context.

Raymond Ko20:01:14

Thank you for your thoughts.

Dimitri _19:01:29

Hello, how could I model in Clojure an Intermediate Represention like llvm ? or just plain ARM assembly for example

andy.fingerhut20:01:44

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.

andy.fingerhut20:01:40

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.

andy.fingerhut20:01:37

A Google search for the terms "clojure processor emulation" turned up some:

Dimitri _20:01:45

well it's not for an emulator, just to make somekind of assembler using Clojure as a DSL

andy.fingerhut20:01:03

I have not examined the code of any of them to see how well documented or explained any of them are.

andy.fingerhut20:01:10

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.

Dimitri _20:01:48

I'm looking at it atm

andy.fingerhut20:01:30

Here is one that provides a functional interface to JVM byte code generation: https://github.com/jgpc42/insn

shaun-mahood20:01:35

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

Dimitri _20:01:49

this is exactly what I was looking for ^^

shaun-mahood20:01:00

Fantastic - there are some great talks on https://nas.sr/talks/ if you want to get more into the details, I particularly loved https://vimeo.com/203271192

Dimitri _20:01:27

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 ^^'

👍 4
djanus22:01:22

Here's a sample of the representation in my toy x86 assembler: https://github.com/nathell/lithium/blob/master/examples/stripes.li.clj

djanus22:01:16

basically mirroring the Intel syntax in sexprs

Rory20:01:03

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.

Rory20:01:43

i feel silly asking this because i thought finding such a resource would be easy, so now i feel like i missed something obvious

Rory20:01:59

lol guess i'm learning javascript

andy.fingerhut21:01:12

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.

andy.fingerhut21:01:57

I would recommend asking in that channel and you might get more responses

Carl Waerner23:01:06

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: @test and I want to do (vals @test) 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.

4
andy.fingerhut23:01:56

FYI, there is a #vscode channel on this Slack that may have more participants who know

seancorfield23:01:08

Sounds like paredit "slurp" which may be bundled with Calva? (there's a #calva-dev channel as well, for Calva users)

Carl Waerner23:01:56

Thank you! Slurping was what I was looking for. It was CTRL + Right/left arrow

Matti Uusitalo03:01:52

There's more! Check out https://calva.readthedocs.io/en/latest/paredit.html Structural editing is really handy way to write clojure code

derpocious04:01:37

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. 😁

derpocious04:01:10

Probably highlighting it + open paren + deleting the old ones is easier?

seancorfield04:01:45

Sounds like regular drag'n'drop editing to me @U2UJ5Q8LD?

derpocious04:01:26

well after all it is visual studio code. haha

derpocious04:01:50

I wonder when audio studio code is coming out

seancorfield04:01:59

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.

4
derpocious04:01:01

or visual reality studio code

seancorfield04:01:23

Changing the subject a bit, have you seen the videos of devs who can drive their entire IDE/editing experience just using their voice?

seancorfield04:01:00

There was a talk at, I think, Strange Loop about it several years ago... it's online somewhere... and there has been at least one more recently...

😲 4