Fork me on GitHub
#clojure
<
2021-07-30
>
Jim Newton09:07:52

I looked at the documentation of butlast and droplast. I must admit that I don't understand the difference. there are some examples, but but I was unable to reconstruct the difference by looking at the examples.

thheller09:07:55

drop-last takes an optional n for number of items to drop. without that it defaults to 1 and essentially being the same as butlast. eg (drop-last 2 [1 2 3])

nbardiuk09:07:31

another difference is at runtime. butlast returns processed result (in linear time) and drop-last - lazy sequence (constant time), it will spend time dropping when sequence is consumed. Also drop-last will not materialize input lazy sequence - useful if input sequence is expensive to build

Azzurite20:07:30

anyone know of a knapsack solution library for clojure/java?

Jakub Šťastný21:07:18

Hey guys, I have a bit of a generic question: discoverability of functions in CJ. In an OOP language, if you have an object, the object will have all the methods bound to it and – at least in Ruby – it's very easy to discover them: [].methods will give me all the methods for an array. I can want to know what are the methods that are specific for array, so I'd do [].methods - Object.new.methods. And so on. And given that Ruby is very purely OOP language, everything is a method, so everything's discoverable in this manner. Taken even further, there was a gem, I think it's called what_method or something like that. It allows one to do say [1, 2, 3].what?(6) and it would go through all the array methods, call it and if the result would be 6 in this case, it'd return name of that method (`sum` for instance). So far my way of dealing with this was to Google a method name and if nothing reasonable pops up, then ask in Slack, but I'm sure there must be better methods. How do you discover functions? I'm open to a wide range of suggestions, for instance I'm yet to set up LSP, let's see whether that helps, I haven't really used it ever, so I have no clue. Cheers!

seancorfield21:07:36

Given that Clojure is open for extension by design, there's almost never going to be a fixed number of functions that could apply to some value -- but the cheatsheet doc probably would help narrow your search. I think there also used to be a service run by someone here that you could feed two values and it would try to deduce which single function would transform one to the other... I don't remember its name/URL or who wrote it...

Jakub Šťastný21:07:57

OK. Change of the mindset is required then. Noted 🙂

emccue21:07:09

presumably systems like core.typed, spec, or malli can assist static tools

emccue21:07:21

but afaik we aren't there yet

dpsutton21:07:38

The often overlooked superpower of Clojure is that the runtime is queryable

emccue21:07:02

like if you had some global function registry, you can take a schema or an example input and show all functions for which the example would be valid input

dpsutton21:07:23

namespaces and vars have documentation attached to them and queryable. (doc clojure.test) gives an essay about how to test things.`(apropos "var")` lists functions that might be relevant for vars. (find-doc "var") will search documentation for what functions talk about vars in the documentation

👍 3
deleted21:07:25

@emccue that would be awesome

emccue21:07:44

let me see if I can whip up a proof of concept

👍 2
Jakub Šťastný21:07:42

@emccue yeah I was wondering something along these lines, with spec.

Jakub Šťastný21:07:49

@dpsutton OK find-doc sounds promising.

dpsutton21:07:25

check out (dir clojure.repl), (source source) and (doc doc) 🙂

winsome21:07:44

Does anybody have a recommendation for a tool that can visualize the dependency graph of project namespaces?

winsome21:07:20

Do you know if that will work with deps.edn project?

winsome21:07:25

Looks good otherwise

Jan K21:07:13

I don't think it works with deps.edn

emccue21:07:15

very basic example

emccue21:07:57

only works with single argument functions defined in a very specific way - but i'm sure someone smarter and with more time could generalize it

hiredman22:07:45

someone wrote a site that would search based on example inputs and outputs (not spec)

dpsutton22:07:39

i'm familiar with borkdude's re-find which uses spec. i haven't seen this othe rone

hiredman22:07:46

https://github.com/Raynes/findfn must be what I was thinking of (not a website)

dpsutton22:07:01

great tag line ha

borkdude22:07:36

I used spec because findfn gave multiple "false positives", like things that happen to work but you would probably never use as such.

hiredman22:07:40

sure, I've never used either

hiredman22:07:22

(re-find or findfn)

West22:07:52

(defn julian-day
  "The Julian day is the continuous count of days
  since the beginning of the Julian period."
  [^java.time.Instant inst]
  (let [utc    (.atZone inst (java.time.ZoneOffset/UTC))
        yr     (.getYear utc)
        mo     (.getMonthValue utc)
        year   (if (<= mo 2) (- yr 1) yr)
        month  (if (<= mo 2) (+ mo 12) mo)
        day    (.getDayOfMonth utc)
        hour   (.getHour utc)
        minute (.getMinute utc)
        second (.getSecond utc)]
    (+ (- (- (+ (java.lang.Math/floor (* 365.25 (+ year 4716)))
                (java.lang.Math/floor (* 30.6001 (+ month 1)))
                day) 13) 1524.5)
       (/ (+ hour
             (/ minute 60)
             (/ second 3600))
          24.0))))
So this function satisfies this test.
(let [reference-instant (java.time.Instant/ofEpochSecond 946749600)]
      (is (= 2451545.25 (sut/julian-day reference-instant))))
Is there a library that does this out of the box? I’ve been looking at https://www.threeten.org/threeten-extra/apidocs/org.threeten.extra/org/threeten/extra/chrono/package-summary.html and https://docs.oracle.com/en/java/javase/16/docs/api/java.base/java/time/temporal/JulianFields.html#JULIAN_DAY. I’m having a lot of trouble understanding how to use them though, let alone understand if they work for my use-case.

2
West23:07:15

Nevermind, I totally got it!

(defn julian-day
  [^java.time.Instant instant]
  (let [utc (.atOffset instant (java.time.ZoneOffset/UTC))
        hour (.getHour utc)
        minute (.getMinute utc)
        second (.getSecond utc)]
    (+ (.getLong utc
                 (java.time.temporal.JulianFields/JULIAN_DAY))
       (- (/ (+ hour
                (/ minute 60)
                (/ second 3600))
             24.0) 0.5))))

coby23:07:00

I'm following http://troydm.github.io/blog/2016/04/11/writing-parser-combinator-library-in-clojure/. It's well written but some of the code seems a little non-idiomatic. Specifically, they're using syntax-quoted lists in function bodies to return values that are destructured like regular ol' vectors:

(defn- line-col
 "find out line/column at position p in String s"
 [s p]
 (let [len (.length s)]
  (loop [p p l 1 c 1]
   (if (<= p 0)
    `(~l ~c)
    (if (>= p len)
     `(~l ~(+ p c))
     (if (= (.charAt s p) \newline)
      (recur (- p 1) (+ l 1) 1)
      (recur (- p 1) l (+ c 1))))))))

;; actual usage:
(let [[l c] (line-col ...) ...)
Is there some advantage here to syntax-quoting, or to returning lists rather than vectors?

hiredman23:07:42

syntax quote is basically a templating system

hiredman23:07:00

they are using it to build a list

phronmophobic23:07:31

seems odd to me. I would personally prefer (list l c) over the syntax quote version

hiredman23:07:49

it is fairly uncommon to do that in clojure, because we have some data structure choices that don't require quoting like vectors, but is seems fine

👆 2
hiredman23:07:11

I believe it(the equivalent, but of course not exactly syntax quote) gets used more often in other lisps where you don't have the vector option (I've got some common lisp code that does it a lot)

phronmophobic23:07:49

also intersting to compare the syntax quote version vs. just calling list

> (macroexpand-1 (quote `(~a ~b)))
(clojure.core/seq
 (clojure.core/concat (clojure.core/list a) (clojure.core/list b)))

coby23:07:54

wouldn't have guessed that's the expansion!

hiredman23:07:51

user=>  (quote `(~a ~b))
(clojure.core/seq (clojure.core/concat (clojure.core/list a) (clojure.core/list b)))
user=>

hiredman23:07:19

(done by the reader not the macroexpander)

👍 2
coby23:07:25

oh I see

coby23:07:11

anyway, I think this author is just not super experienced w/ Clojure idioms (based on the nested ifs instead of cond). I'd probably reach for a vector too (or (list a b) ) but wanted to check I wasn't missing something about `