Fork me on GitHub
#beginners
<
2022-11-27
>
dang duomg 19103:11:32

range is a lazy sequence right is there a way to print out its lazy representation every time i enter (range) on the repl it tries to consume this infinite sequence and crash my repl

Bob B04:11:24

the dynamic vars *print-length* and *print-level* might be of interest:

user=> (set! *print-length* 20)
20
user=> (range)
(0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ...)

šŸ‘ 2
jumar09:11:38

you can also simply take some small prefix of the range:

(take 10 (range))

genmeblog09:11:06

Or just (range 10)

jumar09:11:17

Yeh, for this specific case - but take is more general

George03:11:06

there are a few functions, one is (take <number> (range))

Joseph Graham12:11:31

I've written some code which works but seems more complicated than it needs to be. Curious if someone knows a better way? (def misc [[1 2 3 4] [5 6 7 8] [9 10 11 12]]) (apply #(map * %1 %2 %3) misc)

Mark Wardle13:11:15

(apply map * misc)

Mark Wardle14:11:26

Try (map vector [1 2 3 4] [5 6 7 8] [9 10 11 12]) and see that map can take multiple collections and applies the function to the first of each, and then the second etc. etc...

Joseph Graham14:11:14

yep I can give multiple collections to map

Joseph Graham14:11:35

problem is the three collections are in a list

Mark Wardle14:11:53

Just use apply

Joseph Graham14:11:15

yep that is what I do in my example, just seemed a bit convoluted

Mark Wardle14:11:34

You don't need the convoluted anonymous function... just (apply map * misc)

Joseph Graham14:11:23

OK cool I just didn't realise I can do that. Thanks!

Mark Wardle14:11:24

No problem. Has the advantage of handling any number of collections, but of course, stops once one of the collections has been used...

Mark Wardle14:11:46

e.g. (map vector [1 2 3 4 5] [1 2])

Mark Wardle14:11:27

gives ([1 1] [2 2]) which may not be what you want....

Mark Wardle14:11:32

although it often is.... šŸ™‚

Joseph Graham14:11:17

nope this is fine as this example was just psudocode. my real use-case is implementing a "save all" functionality on table of data from a web app. Here is my real code for your curiosity (after applying your fix):

(defn always-vector
  "this function takes something which may or may not be a vector and makes it always a vector"
  [item]
  (cond
    (= (type item) clojure.lang.PersistentVector) item
    (nil? item) []
    :else [item]))

(defmulti app-page-post (fn [request] ((:params request) :action)))

...

(defn modify-habit [habit_id habit_name freq_value freq_unit date_scheduled]
  (db/modify-habit! (map-of habit_id habit_name freq_value freq_unit date_scheduled)))

(defmethod app-page-post "save_changes_habits" [request]
  (let [{:keys [habit_id
                habit_name
                freq_value
                freq_unit
                date_scheduled]} (request :params)]
    (doall (apply map modify-habit (map always-vector [habit_id habit_name freq_value freq_unit date_scheduled])))))

Joseph Graham14:11:41

if you're wondering why I need always-vector it's because of how the framework handles posted data, if there is one item with a given name it's just a string, else it's a vector. which break everything so I need to sanitize that

Joseph Graham14:11:19

well today I've learned something new about apply which is great! thanks

Mark Wardle14:11:01

vecturns most things into a vector. And see vector? Have a good rest of day.

Joseph Graham14:11:34

vec does not do what I want but vector? I can use. thanks!

Knottyman12:11:22

(map inc misc)

Joseph Graham12:11:18

I realise now my minimal example is not really valid

Joseph Graham12:11:59

I've updated my original thread with an example which better captures what I am trying to do

dang duomg 19113:11:02

does clojure expose continuations

delaguardo13:11:46

not from the core, but clojure programs can use new (still experimental afaik) virtual threads from latest JVM 19

Ben Sless13:11:39

iirc continuations jdk have been moved to an internal api

MikeE14:11:33

I'm working a simple proof of concept using the Apache Lucene library. On program launch I'm building an index from a CSV file. I originally was passing a data structure around to all the functions that needed it but that felt unwieldy as I started adding more and more functions to interact with the Lucene search index. The data structure is a simple map in my case that has the needed java objects like a writer, searcher (some of which are expensive to create). I'm not clear what the idiomatic way to do this is in clojure if I wanted to just have a reference in my lucene.clj namespace and reference it from within the functions instead of passing it around everywhere. Should I use a defonce , ref , atom or a memoized function? Note I don't think at the moment I will be changing the data structure which I think would steer me to an atom?

Mark Wardle15:11:07

Hi. I do this using deftype and then pass around as an opaque handle. I then use a systems library (e.g. component or mount or integrant) to handle its lifecycle management in a running application or REPL. Personally I wouldn't use an atom for this. In many situations, I don't need to pass it around, because I then incorporate that opaque handle into a context (e.g. in a server implementation). In my implementation level code, which uses Lucene directly, I do pass around explicit handles to the required Lucene objects e.g. Searcher. Mostly, at that level, because functions do one thing, they only need one of the basic Lucene objects.

Mark Wardle15:11:54

Here is an example: https://github.com/wardle/hermes if it is of any help.

MikeE15:11:01

thanks @U013CFKNP2R ! Very helpful. Iā€™m just diving back into Clojure after about a year and forgot about how something like integrant could help here. Thanks for the code sample too.

šŸ‘ 1
mister_m17:11:43

How do I remove a defmulti from my active namespace in the repl so I can redefine it?

mister_m17:11:08

I understand that I'd have to also re-evaluate any associated defmethods

Ben Sless17:11:09

def it to nil Alternatively, wrap the dispatch function next time

mister_m17:11:39

what do you mean def it to nil

Ben Sless17:11:02

(def your-multi nil)

mister_m21:11:03

I'm not really understanding the difference between defrecord and deftype. I have a protocol that I've defined which contains a couple methods designed to operate on an adjacency list representation of a graph. I'd like to create something that contains the adjacency list that implements this protocol. Should I be using defrecord or deftype? For more context, I would like to create a different type or record that represents a Graph that internally uses this adjacency list type as its representation. The end goal being defining several defmulti functions such as walk-graph that can dispatch on the graph's representation to the appropriate defmethod fn that understands the representation. Given the context - are defrecord and deftype what I want for both the adjacency list protocol implementer, as well as the "graph" type that holds an instance of that protocol?

mister_m21:11:56

AFAIK I could have a defmulti dispatching on either a defrecord or deftype by using class to determine the "type" I'm dealing with

mister_m21:11:50

I ran through this in CL with CLOS and was able to use multiple dispatch to do relatively the same thing but I'm just balking doing this in clj

dorab22:11:07

For the difference between deftype and defrecord, take a look at https://clojure.org/reference/datatypes (if you haven't already). I'd go for defrecord and see if that works for all your needs.

mister_m22:11:06

Should work to start

skylize22:11:28

defrecord creates a Record type, which has built-in implementations for a many core protocols, giving it out-of-the-box behavior fairly similar to a Map. deftype creates an empty type, with no implementations of anything except what you implement yourself.

šŸ™ 1
skylize22:11:23

If you can benefit from having key value pairs on your data structure, then Record will likely be easier to get going with than an empty type. The basis fields (the keys named in defrecord) will generally show improved performance characteristics than kv pairs of a map would. Additional keys assoc'ed on later will not get this boost. If you dissoc a basis field, you will lose your custom type, as it gets downgraded to a regular map.

Ed23:11:22

If you're planning on implementing something that requires multiple dispatch you may be better off not using protocols and just sticking to multimethods + data. Protocols are a way of hooking into the high performance single dispatch mechanism provided by the JVM, which is not too say that multimethods are "slow". You may find them fast enough ;)

mister_m23:11:38

I originally was dispatching on "metadata" in the graph data structure I had which communicated the "representation" of the graph but I found that to be a little too fast and loose for my liking. I think I prefer being able to dispatch on the result of the class fn for this specific application at least.

mister_m23:11:58

but yeah, fair point definitely

dorab18:11:06

If you're only dispatching on the class then protocols might be more appropriate. In case you haven't already seen this, take a look at https://cemerick.com/blog/2011/07/05/flowchart-for-choosing-the-right-clojure-type-definition-form.html