Fork me on GitHub
#clojure
<
2017-12-15
>
qqq00:12:59

Does Clojure have a library for "generalized regular expressions" standard regular expression: input = string (pretend its a vector of chars) regex = option ?, repeat *, atleast-one +, way to specify single char / set of chars generalized regular expression: input = vector of arbitrary clojure data regex = option ?, repeat *, atleats-one +, predicates ... that given an element, returns true/fase, indicating whether it's 'in the set' or not is there any library for this?

qqq00:12:21

I guess spec kind of does it, but it'd be nice if there was a library dedicated to this

hiredman00:12:40

why do you say spec kind of does that? spec internally uses parsing with derivatives which can parse context free languages which are a super set of regular languages

andy.fingerhut00:12:48

There might be something like that out there that may be more performance-optimized than spec's current implementation. Certainly I have heard of such things in languages other than Clojure.

andy.fingerhut00:12:36

I don't know how optimized the implementation is, but Racket has something like this: https://docs.racket-lang.org/reference/match.html

andy.fingerhut00:12:05

Maybe core.match does this? I haven't used it myself.

andy.fingerhut00:12:34

The older Java versions, pre 7u6, effectively gave you the choice between reference or copy, by substring always creating a reference, and String constructor allowing you to manually create a copy, if you knew you wanted one. With newer versions of Java, they changed the default, and without a library implementation that works via references you can't get the reference behavior. I suspect they did a lot of performance-testing on real applications before making such an implementation change.

tbaldridge00:12:48

@qqq considered using instaparse ?

tbaldridge00:12:04

Or are you writing a parser to get experience writing parsers?

drewverlee00:12:29

I asked before, then lost the response. Are the clojure d videos up somewhere?

aengelberg00:12:39

instaparse only supports strings; I think he was asking about what spec currently does

qqq01:12:13

@tbaldridge: yeah, what @aengelberg said: I want things that can do "regex" over arbitrary data, instead of just strings

qqq01:12:23

"regex" over vector of arbitrary data

tbaldridge01:12:22

one of these days I really should finish my implementation of OMeta in Clojure

qqq01:12:18

is that the VRPI project ?

tbaldridge01:12:19

That sounds like what you're looking for, a generalized parsing system for both strings, and sequences of stuff

qqq01:12:04

I believe OMeta was from this lab: http://www.vpri.org/

qqq01:12:30

But yeah, you should finish your OMeta in Clojure project. I feel like 90% of my clojure needs can be solved by "if only @tbaldridge finished those projects ...."

tbaldridge01:12:05

Last I worked on it was before spec existed. I think there's a lot of overlap there. OMeta is a bit like a DSL for spec and conform with polymorphism added

qqq02:12:10

https://en.wikipedia.org/wiki/OMeta is confusing me. Is OMeta a Turing-Complete language, or is it on the same laevel as regex/cfg ?

qqq06:12:27

I recall reading somewhere that due to some design decision, Clojure runs into problems if one has top-level files, i.e. src/a.cljc -> (ns a) results in problems can anyone point me at the article I'm referring to?

alexmiller15:12:51

That will work fine, but it’s not recommended as you have not included any namespace qualification and will be potentially colliding with every other user creating a namespace a. Rather, Clojure follows the Java recommendation of starting your package with a reverse DNS of a domain you control or a trademarked name or some other thing that has a chance of disambiguating your code across all the other code in the world.

noisesmith18:12:40

there’s a gotcha also if you use defrecord, defprotocol, gen-class etc. because that creates classes in the default package which is poorly behaved on the jvm right?

noisesmith18:12:53

or are clojure’s classes exempt from those problems?

noisesmith18:12:19

eg. class loading problems if two deftypes both use the default package…

noisesmith18:12:39

I just tried, using deftype and gen-class with namespaces producing items in the default package and yeah it works (likely would have caused problems if I tried to use import though)

tbaldridge06:12:46

It’s not so much Clojure, as it is the JVM

tbaldridge06:12:59

I don’t think that’s a fully valid package name

alexmiller15:12:07

it’s totally fine (just not recommended) - see my comment on prior message

matan09:12:39

@madstap thanks 🙂 the logging xf was indeed my best shot before coming back here!

matan09:12:19

@tbaldridge @aenachronism me too 🙂 and preferably regex builders rather than using the old-school regex language, which is horrible for maintaining code written in it IMO

cmal09:12:07

Hi, I want to get the meta data attached to a function var without knowing the name of the function var at compile time, I tried to do this:

user=> (defn ^::a-meta ttt [])
#'user/ttt
user=> #'ttt
#'user/ttt
user=> (meta ttt)
nil
user=> (meta #'ttt)
{:user/a-meta true, :arglists ([]), :line 11, :column 1, :file "NO_SOURCE_PATH", :name ttt, :ns #object[clojure.lang.Namespace 0x52d645b1 "user"]}
user=> (meta #'(symbol "ttt"))
CompilerException java.lang.ClassCastException: clojure.lang.PersistentList cannot be cast to clojure.lang.Symbol, compiling:(NO_SOURCE_PATH:15:1)
It failed because the #' is a reader macro. If the function name is defined at runtime, are there any ways to get a function's meta data?

schmee09:12:32

@cmal (meta (var (symbol "ttt")))?

bronsa09:12:00

that's not how var works

bronsa09:12:18

use resolve

qqq10:12:53

1. most if ... I write are atleast three lines: one for condition, one for then, one for else branch 2. C has test ? true : false 3. does clojure have a nice macro for that ?

bronsa10:12:31

if itself?

bronsa10:12:43

how is test ? true : false any different than (if test true false)

qqq10:12:47

it's hard to read

qqq10:12:53

when squished on a single line

qqq10:12:01

I like the ? and : to separate the conditions

qqq10:12:25

in practice, do you write single line (if test true-expr false-expr) code ?

qqq10:12:33

maybe I'm just not used to eading them

matan10:12:26

Is there any standard file reader transducer? Something that can be used to stream-read from a file, that can be used within a transducing process? (meaning e.g. composed with other transducers) (edited) Or should I work up a transducer around lazy file reading myself, i.e. from something like this?

matan10:12:40

(defn text-file-reader [filepath reader]
  (with-open
    [file-reader (reader filepath)]
    (line-seq file-reader)))

qqq10:12:06

(empty? 23) throws an exception is there a wa to say: (and (.... is a collection) (empty? ...))

Prakash10:12:21

there is seq?

Prakash10:12:04

also, u can use a seq to check for empty or nil values. (seq []) returns nil

bronsa11:12:11

@qqq one of coll? seq? seqable? depending on what you need

matan11:12:24

Adding to my transduction question three hops above 🙂 is there a core library test function for a newly-written transducer "playing by the rules"? (the rules as per "https://clojure.org/reference/transducers#Creating Transducers")

andrea.crotti11:12:38

given something like

(def myv [:a :c :b])
(def mym {:a :anew})
I need a function to simply do the replacement and get
(:c :b :anew)
(the order doesn't matter)

andrea.crotti11:12:51

something like this works but it's a bit insane (keys (clojure.set/rename-keys (zipmap myv (range 3)) mym))

andrea.crotti11:12:16

any better alternatives?

schmee11:12:18

time for another Specter solution 😄

schmee11:12:29

(transform ALL #(get mym % %) myv)

andrea.crotti11:12:41

ah nice can't use it in this project though

andrea.crotti11:12:50

we have medley at least

andrea.crotti12:12:00

but not sure it helps in this case

schmee12:12:21

are you not allowed to add dependencies?

bronsa12:12:37

user=> (def myv [:a :c :b])
#'user/myv
user=> (def mym {:a :anew})
#'user/mym
user=> (replace mym myv)
[:anew :c :b]

andrea.crotti12:12:42

well we have to agree on which to add, and it was agreed not to add specter

bronsa12:12:53

I get that people like specter but clojure.core is often more than enough

schmee12:12:08

did not know about replace!

andrea.crotti12:12:09

ah nice yes replace is what I needed 😄

schmee12:12:23

there are too many functions in core to remember them all 🙂

schmee12:12:40

btw I also prefer sticking to core as much as possible

fmind12:12:22

I started to learn Specter today, the lib is amazing !

fmind12:12:42

it becomes less scary when you read the List of Macros and List of Navigation on the wiki

andrea.crotti12:12:13

and similar thing (still without Specter), from

{:a 1
 :b 2}

{:a inc}
I want to map to the values but depending on the key, so
{:a 2
 :b 2}
in this case

andrea.crotti12:12:38

there is map-values in medley but it's not quite the same

andrea.crotti12:12:07

I could split the map many submaps, apply the transformations and merge them all maybe

andrea.crotti12:12:11

this works for example

(into {}
      (for [[k v] (seq mm)]
        [k ((k tr identity) v)]))
but other suggetions welcome

schmee12:12:41

I think that one’s readable 👍

bronsa12:12:22

user=> (def a {:a 1 :b 2})
#'user/a
user=> (def b {:a inc})
#'user/b
user=> (reduce-kv update a b)
{:a 2, :b 2}

andrea.crotti12:12:17

nice another point for @bronsa 👍

schmee12:12:12

slick 👍

andrea.crotti12:12:53

and last one, from

(def m {:a 1 :b 2})
(def order [:b :a])
to [2 1] ?

andrea.crotti12:12:27

I just did

(for [f fields]
    (f m))

andrea.crotti12:12:56

mm can just do (map #(% {:a 1 :b 2}) [:b :a]) actually

bronsa13:12:01

or even better, (map {:a 1 :b 2} [:b :a])

fmind12:12:44

do you know a function that executes a form and returns nil on Exception ?

fmind12:12:56

I though I knew it, but I can't remember ...

mpenet12:12:00

if you really need a fn you can easily wrap it

fmind13:12:18

@mpenet got it

(defmacro ex-nil "Return nil if body throws an Exception"
  [& body] `(try [email protected] (catch Exception ex#)))

mbjarland13:12:33

a bit late to the game but finally got time to take a look at scope-capture - really cool and extremely useful, can definitely see myself using this going forward

fmind13:12:49

is someone familiar with clj-time ? Why is this not valid

(f/parse-local (f/formatter "EEE MMM dd HH:mm:ss yyyy z") "Thu Apr 24 10:27:52 2014 CEST") => Invalid Format: is malformed at "CEST"

mbjarland13:12:53

I think the last time zone spec needs to be more z's

fmind13:12:17

OK ... apparently, joda time cannot parse 'z' zone name http://www.joda.org/joda-time/key_format.html

mbjarland13:12:46

wow, did not know that, that's a pretty major omission

fmind13:12:18

yes ... I couldn't agree more !

fmind13:12:56

I think the format was meant for human, not machine

fmind13:12:16

@mbjarland thanks for the help, I think there is no answer to deal with the text timezone properly

mbjarland13:12:30

yeah, seems like it

fmind13:12:39

so this is the "hack" I found:

(def CERT_DATE_PARSER (comp (fn [x] (f/parse (f/formatter "EEE MMM dd HH:mm:ss yyyy") x))
                            (fn [x] (str/replace x #"(\w+ \w+ \d+ [0-9:]+) (\w+) (\d+)" "$1 $3"))))

mbjarland13:12:04

just wrote something to set the time zone on the formatter, but 1. CEST is not one of the ids and 2. if you get the time as a string it doesn't exactly solve your problem

mbjarland13:12:30

(def fmt (.withZone (f/formatter "EEE MMM dd HH:mm:ss yyyy") (org.joda.time.DateTimeZone/forID "Europe/Paris")))
(f/parse-local fmt "Thu Apr 24 10:27:52 2014")
works, but like I said, no CEST

mbjarland14:12:35

@fmind you always have SimpleDateFormat:

(.parse (java.text.SimpleDateFormat. "EEE MMM dd HH:mm:ss yyyy zzz") "Thu Apr 24 10:27:52 2014 CEST")`

fmind14:12:25

it works 🙂 thanks !

fmind14:12:54

I discovered specter yesterday, it's hard not to become addict

fmind14:12:08

I wonder if there is something similar in Python

danm15:12:24

@mbjarland Try asking in #cursive ? Might get a better response there

danm15:12:38

Aah, you have 😉

mbjarland15:12:27

yeah, realized a tad late that there was a channel for cursive

mac15:12:25

I am trying to implement a algorithm that updates objects in a list. The update function takes each object and the list itself (the other objects) as updated so far. With an imperative approach this is easy using mutability (a for loop and indexes), but what is the best approach to doing this in Clojure? I have tried a reduce, but that of course only passes the original list to the reducing function.

New To Clojure15:12:37

@mac reduce doesn't pass the original list, it passes to function each element and result of previous function evaluation

New To Clojure15:12:23

@mac based on original message I guess map nested in let would work here

mac15:12:45

@ghsgd2 Yeah, I get that I meant to write the objects (maps in this case) from the original list.

New To Clojure15:12:31

could change elements in function if they're atoms or volatiles

New To Clojure15:12:33

also there's doseq

seancorfield16:12:26

@mac can you explain a bit more about what the algorithm actually achieves?

seancorfield16:12:51

The approach in Clojure is usually to take one step back from the (traditional) implementation and think about the problem holistically instead.

mac16:12:32

@seancorfield I can. It updates the position of planets. The new position of a planet depends on its own previous position and the position of the other planets - new position if they have already been updated and old if they have not.

bronsa16:12:31

(reduce-kv (fn [planets i planet] (assoc planets i (new-pos planet planets))) planets planets)
something like this

bronsa16:12:43

you can use planets as both accumulator and collection over which to reduce

dpsutton16:12:19

(defn new-position [solar-system planet]
  ...)
(defn update-solar-system [solar-system-state]
  (map (partial new-position state) solar-system-state))

(def universe-time (iterate update-solar-system initial-universe))

dpsutton16:12:24

depending on how you store the state of the solar system. as a list, a map, etc

fmind16:12:16

(defn reposition [planets]
    (map (partial new-position planets) planets))
`

fmind16:12:36

but you have to define new-position to take the list of planets first

bronsa16:12:36

no, using map is not correct

bronsa16:12:53

note that in @mac's js version, each invocation of newPosition takes the updated planets map, not the original one

dpsutton16:12:52

good point.

bronsa16:12:06

reduce is the natural way to express this in clojure

fmind16:12:12

@bronsa @dpsutton agreed, I though the planet object did not change after each iteration

mac16:12:21

@bronsa Yes, that is correct. This is actually what tripped me up. Planets is a vector of maps, but reduce-kv works anyway as far as I can tell.

bronsa16:12:49

yeah reduce-kv supports vectors

seancorfield16:12:58

reduce is the traditional solution for state + rules for state change => new state @mac

seancorfield16:12:14

(for a given set of events -- in this case the set of planets acts as both the initial state and the set of "events" that trigger state change)

mac16:12:25

@seancorfield Yes, I was missing the idea of using planets as both the accumulator and collection over which to reduce, as mentioned by @bronsa.

adamvh17:12:55

@mac are you doing gravitational dynamics?

adamvh17:12:35

because if so you're making it unnecessarily difficult from a programming standpoint

adamvh17:12:00

since from a physics standpoint you'd like to do one pass over the planets and calculate force

adamvh17:12:20

and then another pass to update momentum

adamvh17:12:25

and another pass to update position

adamvh17:12:13

although for speed probably the best thing to do is to solve for the gravitational potential on a grid and then interpolate to get forces, depending on how many planets you have

adamvh17:12:31

i doubt there's a good poisson library in javascript, haha

adamvh17:12:19

ya, from a physics POV, that code would be better if it accumulated xpp and ypp in arrays

adamvh17:12:51

and only actually moved the planets after it had calculated that for all of them

adamvh17:12:33

splitting hairs, probably; the errors from doing it as linked take many orbits to be visible

adamvh17:12:09

(comp (map #(update-position planets)) (map get-force))

adamvh17:12:25

would give you pretty much what you need

mac17:12:32

@adamvh I also had a sneaking suspicion that my original was actually more correct, but the constants are calibrated to work with the js version, which is quite sensitive to starting conditions since it is inserting a tiny space-ship into orbit around mars. Not that I really understand the physics very well 🙂

kwladyka17:12:55

(def queue (agent []
                  :error-mode :continue
                  :error-handler (fn [a ex]
                                   (l/error ex "slack agent failed"))))
Is there easy and simple way to achieve :error-mode :retry ? 🙂 Just from time to time sending messages to slack fail and I don’t want lose them. * It can be achieve in whatever way. :retry example was to easy describe my needs.

hiredman17:12:46

(send-off ... (retry fn) ...)

hiredman17:12:02

(defn retry [f] (fn x [& args] (try (apply f args) (catch Throwable t (apply x args)))))

kwladyka20:12:50

thx, after all I did this:

(def queue (agent []
                  :error-handler (fn [a ex]
                                   (l/error ex "slack agent failed")
                                   (restart-agent a @a))))

qqq19:12:27

inside a (fn [] .... ) is there a way to "refer to self, i.e. the function being defined" -- and this is not via recur

Quan Nguyen19:12:24

Why are you not able to use recur?

markmarkmark19:12:41

you can name a fn (fn f [] …)

qqq19:12:25

because I need to call the function two/three times, in a tree like fashion, it's not a loop

noisesmith19:12:01

yeah, that’s why the (fn f [] ...) syntax exists, it’s the straightforward way to do this

noisesmith19:12:26

though if two functions need to do this mutually, letfn exists for that purpose and no other

qqq19:12:57

ah, the (fn f [] ...) syntax gives it a name I can refer to it by; no idea howI missed it all these years; thanks!

noisesmith19:12:19

extra bonus - when you use (fn f [] …) the name “f” will show up in a stack trace

noisesmith19:12:44

sometimes I name my fn even if it doesn’t self call just so my stack traces will make a little more sense

noisesmith19:12:23

it makes me want versions of partial and comp and complement and fnil etc. that take a “name” parameter too frankly

justinlee19:12:25

How does the keyword-as-accessor syntax actually work in the language? E.g. (:b {:a 1, :b 2}) Is this just special syntax built into the language or is there some reason why keywords can act as functions in this way?

noisesmith19:12:38

it is not a syntax, keywords are functions

noisesmith19:12:56

symbols, hash-maps, sets, and vectors are also functions

noisesmith19:12:22

at one point they argued about making regexes functions too but they opted not to do that

bronsa19:12:45

ah? do you remember when ?

noisesmith19:12:16

no - I have seen discussion about it but forget the details

hiredman19:12:38

I've never seen serious discussion about it, just perennial whinging about how nice or how cool it would be if it was the case

chris19:12:34

specifically, keywords implement IFn

noisesmith19:12:55

@chris right when I say “is a function” about clojure that means “implements IFn”

justinlee19:12:04

But there must be something special about them because there are an infinite number of them and they spring forth whenever you use them

noisesmith19:12:22

@Justin how’s that different from fn?

chris19:12:27

is that different from how a function works?

bronsa19:12:35

or a symbol

bronsa19:12:52

the reader interns symbols/keywords

noisesmith19:12:14

but symbols can have metadata so they do something different about the interning right?

bronsa19:12:42

yeah symbols just have their internal string interned

bronsa19:12:54

actually since a few versions ago that might not be true, I can't remember

hiredman19:12:57

and interning has nothing to do with being used as a function

bronsa20:12:53

true, I was just answering how they "pop out of existence"

hiredman20:12:09

(foo a b c) in clojure is something like ((IFn)foo).invoke(a, b, c) in java

justinlee20:12:30

I previously just thought of them as identifiers that had some concrete unique representation that allowed them to be used as keys in a map. But then they can also be used in the first position in a list (which I think of as “function” position but I’m sure it has a more precise name). I suppose the point is that they are instantiated as lookup functions the moment the reader sees them and the reference to that lookup function is what is used as a key?

hiredman20:12:53

they are instances of clojure.lang.Keyword

hiredman20:12:59

which implements IFn

hiredman20:12:08

clojure.lang.IFn

justinlee20:12:26

oh right. okay got it

noisesmith20:12:40

@Justin also, regarding “allowed to use them as keys in a map” that’s true of literally any value in clojure

bronsa20:12:14

(:foo {:foo 1}) becomes something like new Keyword ("foo").invoke ( {:foo 1 })

hiredman20:12:24

any object on the jvm that doesn't replace Object's hashCode and equals with methods that throw execeptions

bronsa20:12:40

which is implemented roughly as {:foo 1}.get(this)

hiredman20:12:07

clojure values just make better keys then most objects on the jvm

chris20:12:48

immutability is a good idea™

noisesmith20:12:32

ahh right- you can use a mutable thing as a key, but if the mutation changes the hash or equality you will have a bad time haha

justinlee20:12:07

@noisesmith Right that was phrased awkwardly. Keywords are a little interesting because unlike something like a let binding or a formal parameter, what you call the keyword actually changes something in memory. I guess that’s no different from a string literal but it has always felt unusual to me because a keyword looks like a formal name rather than data.

justinlee20:12:20

At least I think that’s right.

bronsa20:12:31

keywords are data, not labels

bronsa20:12:48

just like a string or a number

hiredman20:12:08

same with symbols

justinlee20:12:24

Thanks yea that’s important to remember. Because to my C/C++/JS mind they look like names.

hiredman20:12:34

(in fact they are listed under data_structures on http://clojure.org, https://clojure.org/reference/data_structures)

bronsa20:12:14

apart from reader macros, there's no labels or language syntax that's not reified as a value

noisesmith20:12:54

let bindings are sneaky to find, and even sneakier to do anything with as data haha but yeah https://gist.github.com/noisesmith/3490f2d3ed98e294e033b002bc2de178

mikerod20:12:15

Beyond the (keys &env) I wouldn’t really consider let-bindings to be “reified” (officially) in clj

noisesmith20:12:34

right - but that snippet proves they are reified

hiredman20:12:10

you are reading compiler state using the macro and generating code to reproduce it at runtime

noisesmith20:12:30

oh… that is different OK

hiredman20:12:04

what bronsa meant is (let [a 1] a) is not "syntax" as such, it is a list containing a symbol, a vector, and another symbol

hiredman20:12:43

user=> ((fn [x] ((x {:a {:a 1}}) x)) :a)
1
user=> 
might be interesting to puzzle out when learning about keywords

matthavener20:12:04

anyone know why

:1
is a valid keyword but
:foo/1
is not?

matthavener20:12:32

( or maybe they’re both invalid and :1 just happens to work? )

bronsa20:12:25

they are both invalid literals

bronsa20:12:35

:foo/1 happens to work but it's still invalid

noisesmith20:12:43

https://clojure.org/reference/reader - yeah my “read” of this is that :1 is illegal but accidentally works in some cases

hiredman20:12:48

well, no, right? because the reader doesn't determine what a valid keyword is

bronsa20:12:06

yep, I said literal

noisesmith20:12:09

maybe a strict reading of that reference would also imply : is bad, and keywords of that form are used in core libs (and it’s neither here nor there but the reader does accept them)

noisesmith20:12:25

it was unsettling to see that being used on purprose

andy.fingerhut20:12:31

If an implementation doesn't stop you, someone somewhere will do it. 🙂

hiredman20:12:55

and think it is a great idea

alexmiller20:12:05

there is a lot of background on this - the regex for keywords in the reader is actually wrong, which is why it works

alexmiller20:12:21

we “fixed” it in 1.6 and found out it broke a lot of existing code

alexmiller20:12:28

so we unfixed it

andy.fingerhut20:12:12

Taking advantage of such behavior does put you at some kind of risk of a future version of Clojure reserving characters for other purposes, and now either you update your application or don't run it or its data with that version of Clojure. Given sensitivity to backwards compatibility by core team, I doubt they would break such things for fun.

alexmiller20:12:36

I’d say at this point that there is no chance we will take that away

alexmiller20:12:45

we did break it, and it wasn’t fun

aengelberg20:12:25

I notice one can now override *reader-resolver* in Clojure 1.9. Has anyone tried this? What scenarios is it useful for?

aengelberg20:12:38

If I wanted to write a utility that overrode *reader-resolver* to do cool stuff, I would have to alter-var-root it rather than bindings it so that I can load code with that new reader resolver in place, right?

alexmiller20:12:56

it’s useful if you want to have control over how namespace-sensitive things resolve (like autoresolved keywords)

aengelberg20:12:32

Looks like I can affect the behavior of read-string:

user=> (binding [*reader-resolver* (reify clojure.lang.LispReader$Resolver (resolveAlias [this sym] 'blah))] (read-string "::a/b"))
:blah/b

aengelberg20:12:54

It seems to me that that's the only thing I can do with binding

aengelberg20:12:59

Just want to make sure that's accurate

alexmiller20:12:30

really best for programmatic reader cases where you are creating the environment (not for general code loading in the RT)

aengelberg20:12:47

gotcha, that's what I wanted to confirm

aengelberg20:12:08

I was hoping I could write myself a with-aliases macro that lets me define arbitrary aliases in local scope or something

alexmiller20:12:16

I think reading has already been done at macro time so that wouldn’t work

aengelberg20:12:36

unless I use push-thread-bindings and pop-thread-bindings....

aengelberg20:12:05

then I could write a defalias macro that pushes a new *reader-resolver* for the remainder of that file

aengelberg20:12:15

but then I don't know when to pop it

bronsa20:12:43

having a push-thread-binding escape its lexical context is not a good idea anyway

aengelberg21:12:13

(ns my.ns)

(defalias o other.ns)

::o/a-keyword

(end-aliases!)
troll

bronsa21:12:07

if your push-thread-binding gets executed from within a binding, that binding ill pop the wrong thing

hiredman21:12:27

if you are going to be gross, hijack the dispatchMacros table in the reader

aengelberg21:12:13

brb forking Clojure

briantrice22:12:52

Am I missing something, or does Clojure not have a way to refer to a piece of code from a docstring? I’m hoping to hyperlink between namespaces when an implicit dependency exists. I’ve considered using #_ macros but that invokes a (requires) clause I’d rather avoid.

briantrice22:12:21

IDE stack is Cursive with a close fallback of Emacs/etc

phronmophobic22:12:42

you could use metadata

arrdem22:12:00

@briantrice there is no standardized docstring markup for referring to symbols.

phronmophobic22:12:12

instead of encoding it in the doc string and then having a way to parse it out

phronmophobic22:12:14

you could just be explicit with meta data (defn ^{:refers-to 'other.name-space} foo [] 42)

briantrice22:12:30

@arrdem okay! glad to know it for sure

arrdem22:12:55

Some authors use Markdown style backtick blocks. I personally like to use #'foo or #'other-ns/foo var notation in backtick blocks in docstrings.

briantrice22:12:59

@smith.adriane okay that is interesting. I can do it without require, then? I’ll see whether cursive/etc pick up on it

arrdem22:12:14

Some of the tools support wiki-style [[my.other/thing]] references.

briantrice22:12:14

#' is also a good point, thanks

phronmophobic22:12:54

the meta-data keyword is completely made up by me, so if you wanted ide support, you’d have to add it

phronmophobic22:12:46

just trying to say that this isn’t a standardized practice. just a suggestion for how you could start one if you wanted

briantrice22:12:54

Cursive is trying hard to resolve it, though. just failing…

briantrice22:12:32

hm. of course the real problem is that this is across Clojure/ClojureScript code where I can’t exactly write cljc.

briantrice22:12:10

maybe I will find a way to cljc it, but for now, I have to keep the people reading the code aware.

briantrice22:12:12

Where would I RFC on such a thing?

briantrice22:12:09

I’ll take it to #cursive in case it appeals…

derpocious22:12:10

Hey all, I'm wondering in clojure since there aren't really object methods how do I know what functions I can use on something?

derpocious22:12:40

For example, how do I know all the methods I can use on a channel made from core.async's (chan)?

derpocious22:12:19

thanks, but that doesn't really answer my question. For example, I'd expect from that philosophy to be able to do "nth", "count", "map", etc

derpocious22:12:35

But none of these actually work so I'm wondering what are the methods that work for chan

qqq22:12:31

I'm not sure if this helps either: you can lookup all the protocols that chan implements, then look at functions that depend on those protocols

qqq22:12:53

also, I'm pretty sure you can do something map/transducer like on chans

phronmophobic22:12:54

for channels specifically, most of the functions that work with channels can be found at https://clojure.github.io/core.async/

matan22:12:55

hey guys, is there any file reader transducer in any core library? Something that can be used to stream-read from a file, as part of a transducing process? Or should I work up a transducer around lazy file reading myself (which is what I'm about to be doing now)

derpocious22:12:48

@qqq I'm not really sure what you mean. How would Iook up all the protocols for channel?

derpocious22:12:38

@smith.adriane Those are just functions within the core.async namespace, NOT functions that I can use on a ManyToManyChannel

matan22:12:44

@reborg yes, but doesn't that snippet show a transduction that is specific to the file reader? doesn't it go against the motivation for transducers? as in being generically applicable regardless of the actual input source

phronmophobic22:12:53

@derpocious, there’s not really a great way to obtain a list of every function that takes a ManyToMany channel as it’s first argument

matan22:12:28

@reborg mmm on second thought maybe you are right and this is just trivial

reborg22:12:31

Do you have a specific idea about how a possible API would look like in this case? Trying to understand if there is room for improvement

matan08:12:09

@reborg thanks for having responded! I am not sure why most experts ignored, is it because they seldom write transducers or they considered the topic too basic to their taste

matan08:12:05

Your implementation looks flawless in also closing the file "the transducer way"

phronmophobic22:12:19

and you often want to program against abstract types instead of concrete types

phronmophobic22:12:41

2) since clojure’s protocol system is open

phronmophobic22:12:12

at runtime, more protocols can be extended to work with the concrete type of ManyToManyChannel

phronmophobic22:12:52

3) in addition, anyone could write a function that takes a ManyToManyChannel as it’s first argument

phronmophobic22:12:03

or if the ManyToManyChannel was added to more protocols, then at any point, any protocol can start working with ManyToManyChannel

phronmophobic22:12:53

for most clojure functions, the types that functions expect aren’t annotated anywhere

phronmophobic22:12:50

so even if you went through every function in every namespace, there’s not typically a good way to ask if a particular function accepts a particular type

phronmophobic22:12:39

basically, clojure tends to adopt an approach that is dynamic and open which makes it more difficult to answer questions like “which functions work with the type?”

phronmophobic22:12:01

but makes a lot of other designs easier

nooga22:12:02

I was under the impression that things like (take 1 (drop 40000000 (iterate inc 1))) would take constant memory but it doesn’t appear so. Could somebody explain what exactly happens here?

nooga22:12:57

I get “Out of memory” on a constrained system while running this

phronmophobic23:12:55

@nooga, how constrained?

nooga23:12:22

it’s http://repl.it so I have no idea, but the memory assigned there must be somewhat small

nooga23:12:48

but that shoudn’t matter if my assumption that this will take constant memory is correct

phronmophobic23:12:39

I think it does take constant memory

nooga23:12:09

my thinking was that iterate will return a lazy seq, drop will basically throw away elements as it goes and first will just cut the remaining lazy-seq and everything will be garbage collected

nooga23:12:27

and those 40M elements won’t be allocated anywhere

phronmophobic23:12:09

that was my impression as well

phronmophobic23:12:54

the one common issue is “hanging onto the head”

nooga23:12:14

I fail to see that in my example

phronmophobic23:12:18

for eg. (def xs (take 1 (drop 40000000 (iterate inc 1)))

phronmophobic23:12:04

sometimes the repl messes things up

phronmophobic23:12:38

since it assigns the whole sequence to *1

phronmophobic23:12:45

which means it is hanging onto the head

phronmophobic23:12:05

try (first (take 1 (drop 40000000 (iterate inc 1))))

nooga23:12:18

but (println (take 1 (drop 40000000 (iterate inc 1)))) will also run out of memory

hiredman23:12:03

who knows what http://repl.it does

hiredman23:12:59

as someone who runs a publicly accessible code sandbox, I can tell you they are never vanilla and extrapolating behavior to the "real" thing is fraught