Fork me on GitHub
#clojure
<
2017-09-04
>
alex-dixon01:09:55

Is there a way to change the REPL prompt for the REPL I’m currently using?

alex-dixon01:09:47

I.e. from “my.ns =>” to something else

Alex Miller (Clojure team)01:09:57

sure, just start a new (embedded) repl and supply your own prompt function http://clojure.github.io/clojure/clojure.main-api.html#clojure.main/repl (clojure.main/repl :prompt #(printf "hi mom (%s) => " (ns-name *ns*)))

weavejester01:09:28

If you’re using Leiningen, then the option is under :repl-options, :prompt, I believe.

Alex Miller (Clojure team)01:09:37

yeah, to be clear that answer was for a clojure.main repl - other repls may vary

alex-dixon03:09:56

Thank you. Made some progress with using leiningen which is what I usually use with Cursive but think I’m going to try the clojure.main repl. When I eval inside IntelliJ using cursive it brings up this and I”m wondering if this is the repl that wasn’t able to accept an exit argument. Think I heard Mr. Halloway mention that in a talk

alex-dixon03:09:50

Doesn’t matter really I can just restart cause obviously I don’t want to be coding in an alert…

cfleming03:09:28

@alex-dixon Yes, you don’t want to run nested REPLs inside a lein (nREPL) REPL or you’ll get that message.

cfleming03:09:42

You could try the clojure.main one, which should work better for that.

alex-dixon03:09:37

@cfleming Thank you. This is exciting 🙂

alex-dixon03:09:44

Googling for nested repls isn’t turning up anything. Is this common practice? Also if I wanted to exit one and get back to the one it’s running in, is that possible?

Alex Miller (Clojure team)03:09:48

By default, no. The repl variant we created for the socket server repl does support a special :repl/quit command that can be used for that. You could steal that stuff from clojure.core.server.

Alex Miller (Clojure team)03:09:23

It's just more function options passed to repl

didibus03:09:24

@donyorm @piegie Its best to just use them, understanding them isn't needed until you need to extend them. Basically, instead of using map, filter, remove, take, etc. on lazy sequence, you should use transducers instead. All it takes is a slight syntax change.

(filter even? coll)
(into [] (filter even?) coll)

donyorm03:09:54

So on a lazy sequence I should try to use transducers, but on a vec or a list I should use the normal functions (map, filter, etc)?

didibus04:09:02

No, instead of lazy sequences. You can think of transducers as eager versions of all the lazy sequence operations. They are implemented as overloads on the same functions with the collection argument removed. So (map inc) is the eager transducer variant of (map inc coll)

didibus05:09:27

The specialty with them is that they won't do redundant loops. So if you (map inc) and (filter even?) over the same collection, it will only loop once over the collection instead of twice.

didibus05:09:23

Personally, I think transducers should have been the default, and lazy sequence should be an opt in alternate, but transducers were introduced later. The only time you don't want to use them is when you really need lazyness.

donyorm05:09:11

that's good to know, thanks

didibus05:09:48

Instead of

(map inc (filter even? coll))
, which is the lazy sequence variant of collection operations, you just remove the collection and to chain them together you use comp instead:
(into [] (comp (filter even?) (map inc)) coll)

didibus05:09:36

And just use them on all things, collections like vector, list, map, set, and also on sequences. And when you want lazyness, only then use the older versions. The syntax difference is that lazy operations are nested, so they all take the collection. And eager transducers variants are not nested, so they omit the collection and you compose them with (comp) instead.

didibus05:09:22

Because of that, you do need to wrap them in something that takes a collection like into or transduce

pj17:09:06

is there a point to using transducers if you're only doing 1 transformation?

pj17:09:33

I can see the performance benefits if multiple transformations are composed

didibus18:09:02

The point is eagerness

didibus18:09:56

Lazyness only introduces complexity onto your code, so unless you explicitly want lazy behaviour, transducer are still simpler.

didibus18:09:53

That said, nothing wrong with the lazy variants, just need to be careful about when they get realized.

didibus18:09:55

You can see a favourite Clojure question is: "How do I force a sequence to realize itself?" And often people say to wrap it in an (into). Amd if you've got nested lazy sequences, then its non trivial to realise it.

didibus19:09:05

So a lot of times, lazyness just trips people over. Even when only applying one transformation.

pj19:09:23

Aha cool, thanks for the explanation!

carocad10:09:01

hey guys, quick question. I just started using the components framework from Stuart Sierra and the reload workflow. One thing that I still dont understand is that for development he recommends to use alter-var-root. Why not an atom together with swap!. I thought that is the recommended way. Is there any benefit in using vars over atoms?

the-kenny11:09:56

carocad: No need to deref it. That's pretty much the only benefit :)

carocad11:09:07

oh, really? I thought about it but I coudnt believe that that would be the only benefit 😄. Thanks @the-kenny

alex-dixon12:09:26

Is there a way to programmatically quit a repl created with clojure.core.server/repl? I’m using Cursive and it quits when I type :repl/quit into the prompt just fine but not when I evaluate :repl/quit from a file

Alex Miller (Clojure team)12:09:57

that repl is interpreting a read :repl/quit keyword as a command

Alex Miller (Clojure team)12:09:56

I suspect the path that you’re following evaluates the keyword, rather than just sending the keyword itself, like (eval :repl/quit)

Alex Miller (Clojure team)12:09:20

the socket server repl does not look at the result of an evaluated expression, just the input

Alex Miller (Clojure team)12:09:27

I suppose it could…. but then any evaluated expression could potentially kill your repl. not sure that’s actually a feature. :)

alex-dixon13:09:05

Yeah…I’m doing something weird as usual. Experimenting with using a REPL instead of bash to work with ssh/docker/containers. I’m changing the REPL prompt to show what host I’m ssh’d into, and when I disconnect I’d like the prompt to go back to the previous user/hostname

alex-dixon13:09:01

I was thinking nested REPLs might help encapsulate some state management but I think I’m in over my head on that one 🙂

cddr20:09:14

Is there something like -> but which works with vectors instead of conses?

didibus23:09:27

Don't think so

cddr20:09:21

I made this by starting with the code for -> and adapting, but wondering whether this is already done somewhere

(defmacro v->
  "Like Clojure's `->` but expects the 'forms' to be vectors"
  [x & forms]
  (loop [x x, forms forms]
    (if forms
      (let [form (first forms)
            threaded (if (vector? form)
                       `[~(first form) ~x ~@(next form)]
                       (vector form x))]
        (recur threaded (next forms)))
      x)))

hmaurer21:09:39

@cddr out of curiosity, what is the use-case?

cddr21:09:23

It supports the DSL I'm working on for kafka streams. e.g. imagine you want to start with a stream, join it to a bunch of other streams, and then map the result through some transformation

(v-> [:stream #"foos"]
     [:join (fn [foo bar]
                   {:foo foo, :bar bar})
          [:stream #"bar"]
     [:join (fn [foobar baz]
                  (assoc foobar :baz baz))
          [:stream #"bar"]
     [:map (fn [foobarbaz]
                    (whatevs foobarbaz))]

cddr21:09:12

That turns into the following which can be interpreted by the evaluator https://github.com/cddr/ksml/blob/master/src/cddr/ksml/eval.clj

[:map
 [:join
  [:join
   [:stream #"foos"]
   #function[user/eval9655/fn--9656]
   [:stream #"bar"]]
  #function[user/eval9655/fn--9658]
  [:stream #"bar"]]
 #function[user/eval9655/fn--9660]]

hmaurer21:09:14

oh, that’s neat

hmaurer21:09:54

is there a reason to use vectors instead of lists there? (I am new to clojure, sorry if it’s obvious)

cddr21:09:22

I'm actually not sure. Was following the example set by hiccup and honeysql which do similar things with a different target

scaturr22:09:18

is there a simple way to convert a qualified map to an unqualified one?

scaturr22:09:32

{::some-ns/name “brian”} to just {:name “brian”}?

eronalves13:09:51

@scaturr I create a simple helper to transform some maps with complex names (ex: {:foo/foobar 1}) to a simple name (ex: {:foobar 1}) treating colls and maps, but I do not expect key collisions, if helps you, please see this link: https://github.com/eronalves/foodship-restaurant/blob/master/src/foodship_restaurant/helpers/keywords.clj

scaturr13:09:54

Many thanks! This is helpful 🙂

eronalves17:09:02

You’re welcome! If you modify something or improve the implementation, please, send me! I will like to improve my own implementation! 🙂

qqq22:09:29

#(into {} %) will take as input a list of 2-item-vectors and produce a hash map as output I want something which can take as a input a list of 3-item-vectors and produce a '2 level' hash map is there a builtin for this ?

hmaurer22:09:22

@scaturr mmh, a general function for this would need to handle key collisions

scaturr23:09:30

ah - good point

hmaurer23:09:15

@qqq oh, check this out:

(reduce #(assoc-in %1 (butlast %2) (last %2)) {} [[:a :b 33] [:a :c 33] [:foo :bar 22]])

hmaurer23:09:25

not quite a built-in function, but…

madstap23:09:21

@cddr Does that really need to be a macro? Your example seems to work fine when I change defmacro to defn and [(first form) x ~@(next form)]` to (into [(first form) x] (next form))