Fork me on GitHub
#beginners
<
2017-09-23
>
Lucas Barbosa17:09:48

Is there any comprehensible guide to emacs + clojure recommended for a beginner?

Lucas Barbosa17:09:07

I have a tiny experience with clojure and absolutely 0 knowledge about emacs

eggsyntax17:09:13

@lvbarbosa absolutely! If you're an emacs beginner (and especially if you have any vim experience), I recommend using Spacemacs instead of vanilla Emacs. If you decide to go that route, check out: https://practicalli.github.io/spacemacs/ or https://spin.atomicobject.com/2017/02/16/clojure-development-in-spacemacs/ If you decide to go with regular emacs, try https://www.braveclojure.com/basic-emacs/ or http://clojure-doc.org/articles/tutorials/emacs.html

eggsyntax17:09:08

Those are all reasonably up-to-date IIRC. There are also friendly #emacs and #spacemacs channels here on Clojurians, and a terrific #beginners channel for asking Clojure questions.

Lucas Barbosa18:09:10

@eggsyntax if I would like to go with regular emacs, is there any difference between using it on my osx bash vs using the gui version?

Lucas Barbosa18:09:49

I mean, of course there is the point where bash is bash and GUI is GUi

Lucas Barbosa18:09:06

but I always thought of emacs as being a terminal editor

eggsyntax18:09:22

Hmm, good question. I'm not sure -- I use spacemacs, which essentially always acts as a gui version (you can get it to be inside the terminal but it's a bit awkward). Because emacs startup takes a second or two, emacsers tend do do long-running emacs sessions, so it kind of makes sense to use a version separate from any particular terminal -- not like vim, where you start & quit instances at the drop of a hat. But either way works really well, it's just a matter of preference.

eggsyntax18:09:34

ie if you need to do some little thing, vimmers tend to start a new instance; emacsers tend to do it in a buffer in their already-running instance. I generally keep my emacs instance running all the time, and I think a lot of folks do the same.

Lucas Barbosa18:09:06

I will try out standard emacs on the gui

Lucas Barbosa18:09:29

learn the basics and then start doing some clojure on it

Lucas Barbosa18:09:40

I’ll definitely try spacemacs later

eggsyntax18:09:12

@lvbarbosa spacemacs is actually easier (IMHO) for beginners. I encourage you to either use spacemacs or some batteries-included emacs distribution, unless you really want to learn it from the ground up. But some batteries-included version will give you a much easier learning curve, and it can be pretty tough trying to learn emacs/vim at the same time as a new language (especially if you haven't done much with lisp or with other functional langs). But your call, of course! 🙂

Lucas Barbosa18:09:16

@eggsyntax I see… I already have a little bit of experience using Clojure, have been studying and practice for the past few months

eggsyntax18:09:40

Oh, gotcha, so it's not both of them from scratch at the same moment 🙂

Lucas Barbosa18:09:06

Yes.. but I am kind of afraid of emacs 👀

Lucas Barbosa18:09:25

That’s why I will dedicate some time to it

Lucas Barbosa18:09:36

I have literally no idea on how it works

eggsyntax18:09:54

Do you have vim experience?

eggsyntax18:09:51

(if so, you'll probably want evil-mode, so you can leverage the key bindings you already know)

Lucas Barbosa18:09:52

Just a little bit, enough for editing files over ssh when needed. Like entering insert mode, exiting insert mode and writing my changes

chris_johnson18:09:11

Default emacs has a pretty good interactive tutorial, though I would also point out that you can get a passable REPL development environment in lots of different editors these days

Lucas Barbosa18:09:00

@chris_johnson I’ve tried Atom’s proto-repl, but there’s something in Atom that doesn’t make me feel good

chris_johnson18:09:05

Atom, IntelliJ IDEA, possibly VS Code (though I haven't gone back to look recently and this was behind Atom last I checked)

Lucas Barbosa18:09:21

I don’t know, there’s an input delay, compared to sublime, for instance

Lucas Barbosa18:09:35

this is basically what I am looking for in Emacs, I want a fast experience

chris_johnson18:09:04

I mean, I'm conversant with all of those editors and I make the conscious choice to use Emacs + CIDER because it is, for me, a whole other class of experience

chris_johnson18:09:23

But if you're worried about the two streams of self-education at once making each one slower, it is entirely possible to learn one first and then the other, that's all I'm saying.

chris_johnson18:09:39

I think learning Clojure and learning Emacs are both very worthwhile endeavors that will give you a really useful perspective even on other languages and editors, and I definitely encourage you to dive in and start having The Best Experience from the get-go

chris_johnson18:09:44

But if it's a choice between An Okay Experience with VS Code and bouncing off the whole project, I would encourage you to go for An Okay Experience. 😄

Lucas Barbosa18:09:50

Well, I am learning just for fun

Lucas Barbosa18:09:07

not any professional requirement or project

chris_johnson18:09:08

That’s the best kind of learning!

Lucas Barbosa18:09:47

Indeed, what I work with has almost nothing to do with programming. Well, I use a declarative programming language to do knowledge engineering, but it isn’t even close to “real” development

chris_johnson18:09:13

So, another thing in addition to the excellent recommendation to grab some kind of batteries-included setup for Emacs is that Emacs itself has a fairly decent built-in tutorial for the basic stuff like moving around in a file, opening files, the sort of conceptual model of how Emacs thinks about things

sundarj19:09:21

i'm another new to Emacs and Clojure - don't want to be overwhelmed, so i'm just using vanilla Emacs for now - then i'll start adding clojure-mode and CIDER once i know more

sundarj19:09:22

already got bitten by using Brave Clojure's setup

Lucas Barbosa18:09:14

But yeah, learning Clojure has been a very nice time

chris_johnson19:09:21

You get to it by launching Emacs and hitting C-h t (`<Control>` and h together, followed by t by itself)

Lucas Barbosa19:09:38

Great, I will try that out soon

Lucas Barbosa19:09:58

thank you guys for the tips, really appreciate them! @eggsyntax @chris_johnson

eggsyntax19:09:11

Anytime 🙂

eggsyntax19:09:45

Seconding @chris_johnson that emacs + cider + clojure really is worlds beyond anything else, it's pretty much a match made in heaven (although Cursive/IntelliJ is awesome; it's just impossible to beat that combo 🙂 ). So yeah, it's a learning curve, but it's got a hell of a payoff...

nimblerabit19:09:06

I could use some help trying to make a bit of code more concise. Right now I have a definition that looks like this:

(def rook
  [{:fn (fn [[x y]] [(inc x) y]) :max nil}
   {:fn (fn [[x y]] [(dec x) y]) :max nil}
   {:fn (fn [[x y]] [x (inc y)]) :max nil}
   {:fn (fn [[x y]] [x (dec y)]) :max nil}])
I don't want to have to repeat so much there, and I'm trying to figure out how to get that same result through a simpler definition, like this (as an example):
{:functions [[(inc x) y] [(dec x) y] [x (inc y)] [x (dec y)]] :max nil}
Hopefully that makes sense. Basically I don't love how I have to repeat so much in that first definition, but I don't understand how to make it more concise. Is there some way to not have to do the anonymous function definition over and over? Any help pointing me in the right direction would be appreciated.

sundarj19:09:43

boot.user=> (defn define-piece [{:keys [x-fn y-fn max] :or {x-fn identity, y-fn identity}}]
       #_=>   {:fn (fn [[x y]] [(x-fn x) (y-fn y)]) :max max})
#'boot.user/define-piece
boot.user=> ((:fn (define-piece {:x-fn inc})) [1 2])
[2 2]
something like this?

nimblerabit19:09:36

This works perfectly, thanks!

sundarj19:09:10

no problem 🙂

sundarj19:09:28

feel free to change the name

gonewest81819:09:05

…jumping in late on the emacs thread so I’ll simply add: keep it simple, especially at first. There is so much functionality you can get buried and feel like you’re never going to get a handle on things. And especially if you use a curated & pre-packaged distro, because those tend to heap in functionality to cover the wants and needs of diverse followers. I would suggest you can get pretty far with basic navigation, editing, search/replace, and interacting in the repl. Get going with that, and when you need another feature (e.g. interactive debugging, refactoring, magit, …) it will be easier to learn just that one new thing.

sundarj19:09:22

thank you for confirming my plan 🙂

nimblerabit20:09:52

How come I can't use + in the name of a binding in a let? I can use most other symbols, I'm confused why + causes an error

sundarj20:09:55

boot.user=> (let [a+y 3] a+y)
3
seems to work for me

nimblerabit20:09:59

Ahh, I suppose it is specifically + and a number then.

(let [1+2 3] 1+2)

practicalli_john20:09:43

I thought you couldn't start the name of a binding with a number

nimblerabit20:09:43

(let [+2 3] +2) also doesn't work, while (let [=2 3] =2) does, so there's something happening with + and numbers

madstap22:09:33

A single + or - followed by only digits is parsed as a number

madstap22:09:47

Scratch that, a single + or - followed by a digit is parsed as a number. +2w isn't a valid symbol either, because clojure (and clojurescript) tries and fails to parse it as a number. So, yeah, avoid doing that in a symbol. And it doesn't matter where it is, in a let or a def or wherever, it is parsed as a number. I don't know if this is documented anywhere, it probably should be.

adamkowalski21:09:24

Hey I am trying to use docker together with Clojure and I’m wondering if anyone has any tips on a workflow for doing so. I was able to setup a container with Clojure + Java + Boot and I can launch a REPL just fine, but if I try to connect to it from the host machine things start to break down

adamkowalski21:09:12

I launched the Boot REPL with a specific port and made sure to expose that same port to the host machine using Docker but it still seems like I am doing something wrong

chris_johnson21:09:22

Hi @adamkowalski and welcome! I think that it would make it easier for us to help if we had a better picture of what you mean precisely by “things start to break down” and “seems like I am doing something wrong” - do you mean that the REPL never connects to the port, or that you get connected but the REPL behavior is not the same as running on the host machine directly, or something else?

adamkowalski21:09:13

Ah sorry about that I should have gave you more context, let me fire everything up again and I’ll give you the exact error messages i’m getting

adamkowalski21:09:27

but it seems like its able to establish a connection and then immediately disconnects

adamkowalski21:09:53

Ok so I launch my clojure container exposing port 3000

adamkowalski21:09:00

Then I run boot repl -p 3000

adamkowalski21:09:17

I open emacs and run cider connect choosing localhost as the host and port 3000

adamkowalski21:09:26

[nREPL] Establishing direct connection to localhost:3000 ... [nREPL] Direct connection to localhost:3000 established [nREPL] Connection closed unexpectedly (connection broken by remote peer) nrepl-send-sync-request: Sync nREPL request timed out (op clone id 1)

adamkowalski21:09:18

I was thinking that maybe I need to change the host from localhost to the ip address of the docker container, but after checking their docs it seems like exposing a port should allow me to access it using localhost on my host machine

ghadi21:09:23

how are you invoking the container @adamkowalski?

adamkowalski21:09:45

docker run --rm -it -p 3000:3000 clojure

adamkowalski21:09:05

where clojure is a container I built that sits on top of the open-jdk8 alpine container

ghadi21:09:13

I think there is an issue with alpine that people have run into https://groups.google.com/d/msg/clojure/89oLNpntj38/_jtLE8jgAQAJ

ghadi21:09:11

I think the root cause is that alpine doesn't do ipv6, but nREPL requests binding on a ipv6 IP port 3000 by default

adamkowalski21:09:16

Thanks for the tip maybe I should try something else. Is that because they don’t use glibc and use musl-libc instead?

adamkowalski21:09:22

oh the ipv6 thing

ghadi21:09:31

yeah it's ipv6 related.

adamkowalski21:09:00

Do you have another os that you can recommend that is pretty slim and still works well for this kindof setup?

ghadi21:09:07

you can probably get around it by specifying boot repl -p 3000 -b 0.0.0.0

adamkowalski21:09:21

or is it best to just bite the bullet and start using ubuntu and just pay for the extra size

ghadi21:09:42

alpine is fine

adamkowalski21:09:17

You are a genius my friend

adamkowalski21:09:22

I added the -b 0.0.0.0 and it all works

adamkowalski21:09:46

I guess 127.0.0.1 isn’t going to work for external ip’s or something or why would that be an issue

ghadi21:09:17

by default nREPL is binding on ::0 (ipv6)

adamkowalski21:09:24

and it needs to be ::1?

ghadi21:09:36

no -- it needs to be 0.0.0.0 for ipv4

adamkowalski21:09:20

alright fair enough. and do you usually just launch boot like that every time or do you just add the configuration options to your build.boot file?

ghadi21:09:33

dunno, not a boot expert.

adamkowalski21:09:06

Alright well thanks for the help 🙂 I’ll be able to take it from here I hope!

ghadi21:09:09

I use a bare socket REPL for my dev

adamkowalski21:09:16

oh interesting

adamkowalski21:09:23

is there a reason why?

ghadi21:09:27

and I use inf-clojure instead of cider

ghadi21:09:43

I don't like nREPL for various reasons, and don't care about autocomplete.

ghadi21:09:24

and other niceties that it provides. it also is a bit laggy. Rich has written a bit deeper about nREPL vs plain REPLs on the mailing list, worth a peek.

ghadi21:09:36

Better than my hot take

adamkowalski21:09:15

Alright i’ll try to find that and read up on it. I’ve mainly just been using boot because it seems like it gives you a really nice composable build pipeline

adamkowalski21:09:55

I used lein in the past, and when I was doing frontend work I used something like figwheel. But if you use one of the lein plugins it seems like they take over your project and its hard to mix orthogonal plugins

ghadi21:09:59

there will be an official dependency fetcher and clojure launcher soon

ghadi21:09:16

both lein and boot are nice for all the other extras that aren't just fetching deps and launching a JVM

ghadi21:09:48

the official launcher will hit package managers soon -- it's already available on homebrew, and linux flavors coming Real Soon

ghadi21:09:28

The official launcher starts very quickly.

ghadi21:09:05

between 0.4-1.1s on a modern machine - which is great compared to what we're used to

ghadi21:09:22

I can't believe no one filed the nREPL bug!

adamkowalski21:09:31

Oh yeah thats night and day haha, maybe it might be reasonable to use clojure for scripts in the future then

adamkowalski21:09:26

But I think its good there is going to be some standardization on how we launch and fetch dependencies. Whenever I try to introduce new people to Clojure that is always one of the hardest part to get them to wrap their minds around.