Fork me on GitHub
#beginners
<
2021-11-01
>
roborbro10:11:33

does anybody in here use evilmode (doom emacs) and can recommend a paredit mode? barfing and slurping and stuff are not bound for me now and was wondering would be a good mode to achieve this

pavlosmelissinos10:11:45

if you don't get any answers here check out #doom-emacs and #emacs

🙌 1
Max Deineko10:11:24

@U02LBDSC1EU if you're looking for structured editing modes in general and not necessarily paredit -- I quite like lispy at the moment; it is available as doom module so you can simply add it in init.el -- you may also try different key themes, I e.g. use

(after! lispy
  (add-hook 'lispy-mode-hook (lambda ()
                               (lispy-set-key-theme '(special paredit c-digits)))))
(in config.el)

🙌 1
roborbro10:11:27

Thanks! will try it 🙂

pavlosmelissinos10:11:00

Never used it! Why would someone prefer it over other structred editing modes @U9TGHG3LP?

pithyless11:11:07

@U02LBDSC1EU I use evil-cleverparens myself

;; packages.el
(package! evil-cleverparens)

;; config.el
(use-package! evil-cleverparens
  :hook ((emacs-lisp-mode . evil-cleverparens-mode)
         (clojure-mode . evil-cleverparens-mode)
         (lisp-mode . evil-cleverparens-mode)
         (cider-mode . evil-cleverparens-mode))
  :config
  (setq evil-move-beyond-eol t)) ; per advice of evil-cleverparens

2
roborbro11:11:11

thanks, mate - always wondering whether that is fear&loathing screenshot or yourself on the profile pic 😆

Max Deineko11:11:07

@UEQPKG7HQ I can offer only little in ways of comparison -- I've only used clojure layer of spacemacs so far (which includes smartparens and lisp-evil-state iirc), parinfer and doom w/ lispy module (which is to be precise & iianm actually a collection which contains actual emacs lispy mode, lispyville, some evil-collection hydra bindings etc). So far the only thing I wouldn't use again is parinfer, with everything else I'd still have to put more time in to gain significant insight. What I appreciate about the lispy module so far is that it's already put together by someone with more experience with evil mode & lisp, I don't have to adjust lots of settings I don't have any preference toward to yet and I can do some structural editing while essentially staying in vi normal mode.

👍 2
pithyless12:11:04

@U02LBDSC1EU 😆 it's me, although it's been a couple of years since that photo was taken...

pithyless12:11:03

what I like about evil-cleverparens is that it may not be the most advanced mode for paredit, but it feels seamless if someone is used to ViM: things like yank, delete, etc. work on balanced sexps instead of newlines and make sure to keep your parens balanced; and barfing/slurping comes down to > and < and where in the form your cursor is.

📎 1
pithyless12:11:04

I have spent more time than I'd like reading the README's and playing with most of the different modes and all have their pros/cons. Just choose one and learn it! :)

☝️ 1
roborbro12:11:05

ye, just tried lispy and it’s great but certainly a lot to learn. thing with cleverparens for me is that it doesn’t to be maintained anymore.. that’s why I started out with lispy and will see. aynways thanks again! 🙂

Benjamin12:11:10

I second lispy

Max Deineko12:11:14

> things like yank, delete, etc. work on balanced sexps instead of newlines and make sure to keep your parens balanced may be worth mentioning for sake of completeness that lispy module does some of that too (e.g. yyp, c$ or ddp in normal mode should at least keep your delimiters in balance) > just tried lispy and it’s great but certainly a lot to learn due to above I found I can get by with a lot of non-lisp-aware-vi-editing commands and [re]learn structural editing options in little bits -- I reckon with evil-cleverparens that'll be possible as well

Benjamin12:11:03

how do you guys go about instrumenting your spec'ed functions in development?

didibus16:11:10

Generally I just have a comment form that turns it on when evaluated

didibus16:11:40

I think some people also use the user.clj namespace, because that namespace is loaded by the REPL, all code inside it will be evaluated in development

didibus16:11:41

Oh, and in some places I've done something like where at the bottom of a namespace I do: (when (devo?) (st/instrument))

didibus16:11:05

So it is instrumented in dev when loaded

didibus16:11:33

But it means you need a way to identify you are running in dev, so a system property for example.

Benjamin07:11:53

alright that's straightforward

Shmarobes14:11:42

Hi! I was wandering if it's possible to do something whenever my program terminates. More specifically, I would like to store some of the program's state in an .edn file, but I can't see a way to do it. I am using morse to write a telegram bot. The template it provided has <!! in -main which seems to block the main thread indefinitely, so I have to exit by pressing Ctrl+C. Is there a way for my bot to always do some cleanup on exit? What would be the proper way to handle this?

1
Max Deineko14:11:49

Possibly Runtime.addShutdownHook() (https://stackoverflow.com/a/11709814)?

👍 1
Shmarobes14:11:12

@U9TGHG3LP Yep, this works, thanks.

👍 1
Febin John James16:11:48

I am trying to create a reframe template with calva and getting this error.

1
pez16:11:45

Hello, happy to see you use Calva! There is no +calva option to the re-frame template. It’s not needed. See https://github.com/day8/re-frame-template#connect-calva-from-vs-code

pez16:11:23

Welcome to #calva if you haven’t found your way there yet. ❤️

❤️ 1
pez16:11:35

Haha - FACEPALM. Please feel invited to fix that doc page! I removed the +calva option from the template, but forgot to update Calva’s docs.

pez21:11:43

Now fixed.

🙌 1
Benjamin17:11:21

Now I'm getting into transducers and I write code like this

(into
   []
   (comp
    (filter :me)
    (map :emoji)
    (map :name)
    (keep #{"📇"}))
   (:reactions msg))
is this strange or cool? I mostly mean the use of 2 map that could be some fn with get-in instead I guess?

🆒 5
Ed17:11:03

or comp ... but it depends on what those transducers are doing ... one of the that I like about transducers is that they're first class things that you can name, so if it makes sense to separate out parts of the process into two pieces, so you reuse them or just to make the code clearer, I think that's still 🆒 😉

clojure-spin 1
Ben Sless18:11:02

Since it gets compiled to functions, it's faster than get-in, actually, although comp of many args has some overhead, I think it's just at call time, not run time, though. Get-in involves iterating over a sequence. You have unrolled it

2
didibus03:11:53

I think they'd all seem fine to me.

shidima18:11:54

I'm looking to convert this to cljs:

let d = new Display({width: 10, height: 10})
I know that I can use (new Display) but how do I pass the object?

Geoffrey Gaillard19:11:56

(new Display #js{:width 10, :height 10})

shidima19:11:51

Aah, thanks. I was looking in the wrong direction 🙂

rberger17:11:59

I can’t tell you how much this tool by @U0FR82FU1 has helped me https://roman01la.github.io/javascript-to-clojurescript/ when I have to do js to cljs translations!

Ronny Li19:11:59

This is a pretty dumb question but I was wondering how everyone here handles the different kinds of nil? I'll try to explain: we have an asynchronous request that fetches some data. Before the data is returned, we assign a default value of nil. Ordinarily we'd replace this value with whatever data is returned from our request. However, if the returned data is actually nil, it's hard for us to tell whether the request is done or not. What would you do in this situation? Thanks!

indy20:11:54

It depends on whether the nil returned as the response is a legitimate value i.e. the server is indeed intending to return nil or whether the nil denotes a failed request. If it is a failed request, then associng some key like :failed? works well.

pithyless20:11:32

@U01BRM3MQET in case you're not familiar, what you described is sometimes referred to as a sentinel value - http://wiki.c2.com/?SentinelPattern - perhaps that will in further research. nil is in fact a common sentinel value in Clojure programs, but as others have mentioned, using a namespace-qualified-keyword (especially one that is unique to the namespace or program) is a good and idiomatic approach as well.

🙏 1
lambdalove 1
pithyless20:11:50

you might occasionally see sentinels in other places where you want to differentiate between nil value and missing value, eg:

(get {:a nil} :a ::sentinel)

dpsutton19:11:57

i usually use some type of keyword. namespaced keywords are particularly lovely for making state machines like you might want right now. {:state :user.request/loading} or pending, or in-flight, whatever`{:state :user.request/suceeded {:name “bob”}}`

☝️ 2
1
Ronny Li19:11:27

gotcha, so we should have another key that tracks the current loading state. Thank you!

dpsutton20:11:27

and good namespaces make this quite useful for finding the code that deals with the state machine. I like them more and more each time i use them

indy20:11:54

Another such question that I’ve had to deal with a lot. How does one order their params? (other than when working with associative collections and seq-like things). I do understand that it depends on how I name the function. But are there any thumb rules? Should the context-like params come at the start? Or should the param that one is going to majorly work on come at the start?

pithyless20:11:01

By params, do you perhaps mean function arguments?

pithyless20:11:50

If so, one rule of thumb to keep in mind is that lots of clojure.core functions are written with the "primary thing" as the first argument (think so it works well with -> threading macro); while functions that generally work with sequences (map, filter, reduce, etc) expect to take the sequence as the last argument (think ->> threading macro).

pithyless20:11:40

Another rule of thumb is probably if you have many arguments, it should be an associative map instead ;)

🙂 1
indy20:11:55

Thanks @U05476190, quite aware of the ordering for associative collections (first arg) and seq-like things (last arg). Was wondering if there was any thing more. :)

pithyless20:11:31

Honestly, it feels like those 2 are enough for most things. Here's 2 more and that about covers all of my wisdom (hopefully someone comes along and shares something smarter):

pithyless20:11:39

Sometimes you're working with an existing env or context, and usually the arglist will look like <env> <primary-arg> <arg2> <options-map>

👍 1
pithyless20:11:38

^ here env, I'm thinking of an open-map that you pass around (eg. could be your ring-request, pathom-env, or component system map)

pithyless20:11:33

and lastly, I've noticed that focusing more on namespaces-per-thing helps clarify arguments; so instead of a function (parse-uuid <string>) I'll have a UUID namespace and my call will be (uuid/parse <string>)

👍 1
sova-soars-the-sora22:11:37

Once you get beyond 3 or 4 params in the arguments / function arity, would highly recommend going to key'd map and using map destructuring

Stuart20:11:14

I've gotten stuck on a Clojure puzzle. Can someone give me a hint ?

(def omnibool ,,,) ; do magic here

;; such that this test passes.
(deftest basic-tests
    (is (= omnibool true))
    (is (= omnibool false)))

phronmophobic20:11:55

Have you re-read the doc string for =?

hiredman20:11:15

another point of attack might be via clojure.test/assert-expr

dpsutton21:11:40

One other thing is that I think this is a fantastic puzzle to skip as a beginner

Stuart21:11:33

why would that be? Is the solution not very 'clojurey'?

dpsutton21:11:45

if you’re a beginner learning the language, it kinda delves into stuff that either a) isn’t very helpful quite yet or b) if you do like the solutions, the motivating example is not great

dpsutton21:11:58

clojure.test/assert-expr is pretty cool but a bit weird for a beginner. overriding equals is interesting but can cause super strange behavior

Stuart21:11:59

ok, so I solved it and expected to see other solutions that were instructive, and they just weren't. I just overode = to return true. ANother solution now I've done it was:

(ns kata)

(deftype Omnibool [] Object (equals [_ _] true))
(def omnibool (Omnibool.))

Stuart21:11:08

I'm not sure what that one is doing.

dpsutton21:11:56

(let [x (reify Object
          (equals [_ _] true))]
  [(= x true) (= x y)])

dpsutton21:11:30

here’s another solution. I think learning about reify is pretty interesting but i don’t think mucking with =s is the best example

👀 1
Stuart21:11:49

so is that an equivalent in soemthing like C# would be creating a function that determines how == behaves for a type ?

Stuart21:11:14

its saying if you have a type Object, use this for doing .equals() ?

dpsutton21:11:28

and this is why it is a bad example i think. they haven’t explained what’s going on, so the solution is just a mystery to you. reify can create an instance of a protocol or an interface. Contrast this with C# where some class implements an interface but is “something else”, here i can just create a thing that implements Object and has a certain implementation of equals. It would be far better if the exercises had introduced you to this kind of stuff

👍 1
didibus03:11:13

Ya, I don't know why someone would basically make it an exercise for you to write bad code

didibus03:11:10

Though I guess you did learn about a few ways to override the dispatch of = on a type

vncz20:11:38

Well I guess you can create a function with an state atom returning true and false according to the number of calls?