Fork me on GitHub
#clojure
<
2019-09-11
>
ag00:09:34

Anyone good at math? It’s funny. I’ve got myself (again) into stupid argument about how Lisp is not less readable because of prefix notation and I’ve been thrown a “challenge” in my face: > simple formula > Combined trip distribution:

f(t) = A (t^B) exp(Ct) where t = t (i,j)

Then t(i,j)=A(i) f(i,j,t) / Sum(A(i) f(i,j,t))
And I’m not familiar with this at all. Can someone help me to write a function for this in Clojure?

ag00:09:36

I’ve tried to google and it’s not helping. I have found bunch of articles about trip distribution methods. Uniform factor method, Average factor method, Fratar method, Furness method, Gravity model, Tanner model, Intervening opportunities model, Completing opportunities model.. holy cow…

emccue00:09:03

dumb, class in college related issue

emccue00:09:23

is there a json parsing library for clojure that can handle multiple top level forms

emccue00:09:47

delineated by arbitrary whitespace

emccue02:09:10

cheshire/parsed-seq

andy.fingerhut02:09:13

@ag I am not familiar with that formula, although I see there is a Wikipedia page for it. Before someone can help you write code for it, I think you (or someone) needs to identify what the parts mean, e.g. f(i,j,t), is that effectively a 3-d matrix/array indexed by integers i,j,t? Or are some of those things real numbers, not integers? The Sum, what is it summing over? j an integer ranging from 1 to N? If so, is N an input? The A(t^B) in the first line, is that the same A as the A(i) in the second line, or a different thing?

ag04:09:52

@andy.fingerhut @U05509S91 I really appreciate willingness to help . The person first presented the formula (just as I showed) and I said: “well it’s like giving someone an arbitrary verse from a Walt Whitman’s poem and ask to present a Latin translation to demonstrate how it is more “readable” than for example its translation to Mandarin.“. The person then posted the following C like code:

loat t[100,100];

float A[100];

float D[100];

float trips[100,100];

for i = 0 to 99 {

sum =0.0;

for j=0 to 99 {
  friction = (t[i,j]^B)*pow(t[i,j]*C);
  sum+=A[j]*friction;
}

for j=0 to 99 {
  friction = (t[i,j]^B)*pow(t[i,j]*C);
  trips[i,j]=D[i]*A[j]*friction/sum;
}
which to be honest confused me even more.

ag04:09:33

I guess it is my own fault. I should’ve been more courteous and respectful. In my defense I can only say that I’m really tired of programmers (experienced and whatnot) spreading nonsense like “Lisp is not readable” etc. Here’s the full conversation: https://www.quora.com/What-is-the-most-brutal-truth-about-the-Clojure-programming-language/answer/Francis-King-5 if you solve this, feel free to post the solution, but please make sure that it is clean and reasonable enough to convince non-believer that Lisp code is not less readable.

andy.fingerhut04:09:57

I've seen pow(x,y) as a C library function that computes and returns x to the power y, but I do not know what a single-argument version does.

ag04:09:07

This whole thing kinda made me want to read more about trip distribution, and trip generation and in general to learn more about the problem. Not for the sake of winning the argument. Just for fun

ag04:09:38

yeah, pow takes the base and a number: https://www.programiz.com/c-programming/library-function/math.h/pow but what’s above seems to be “C like pseudo code” I assume in that case perhaps it is pow2

Daniel Stephens11:09:01

FWIW - my interpretation

;; DATA

(defn t "trip cost" [from to] (if (= from to) 0 1))
(def size 100)
(def locations (range size))

(def A "trips attracted to `to`" (memoize (fn [to] (rand-int 100))))
(def D "trips from `from`" (memoize (fn [from] (rand-int 100))))

(def B "not sure what these are, assuming some constants" 1)
(def C "as above" 1)

;; CALCULATION

(defn a-friction
  [from to]
  (* (Math/pow (t from to) B)
     (Math/pow (* (t from to) C) 2)
     (A to)))

(defn trip
  [from to]
  (let [sum (reduce + 0 (map (partial a-friction from) locations))]
    (-> (D from)
        (* (a-friction from to))
        (/ sum))))

;; OUTPUT

(def trips (into {}
                 (for [i locations
                       j locations]
                   [{:from i :to j} (trip i j)])))

ag18:09:19

oh wow. @ULNRSUK8C Looks nice… thank you

🙂 4
andy.fingerhut02:09:34

Did the people giving the challenge give it in the form that you show there? Or did they just say "look up the Combined trip distribution formula and implement it"?

gerred02:09:50

@andy.fingerhut is more positive than I would be presented with this. 🙂 it feels like as presented, it already hasn't been reduced into a form that is useful for computation, and it doesn't matter if it's in prefix or infix notation.

andy.fingerhut02:09:20

I mean, sometimes I like a challenge, but it helps if I know what is being asked first 🙂

gerred02:09:38

ya. qualified my statement to not be a trolly post. 😄

Yehonathan Sharvit14:09:25

A question related to reify: As I understand reify allows to create an anonymous record by extending an existing record. Is there a way to to the same but non anonymously i.e. to create a record that extends an existing record?

bronsa14:09:02

>As I understand reify allows to create an anonymous record by extending an existing record. this is not correct

bronsa14:09:22

reify doesn't create an anonymous record nor does it extend one

bronsa14:09:16

and there is no mechanism in clojure to extend a class to another class, so no to your question (well proxy I guess, but it's not what you're asking for)

ghadi14:09:51

as bronsa says, reify has nothing to do with records

Yehonathan Sharvit15:09:41

sorry I meant, reify allows to create an anonymous type

Yehonathan Sharvit15:09:03

> While deftype and defrecord define named types, reify defines both an anonymous type and creates an instance of that type. from https://webcache.googleusercontent.com/search?q=cache:y8by8CHJKvgJ:https://clojure.org/reference/datatypes+&amp;cd=3&amp;hl=en&amp;ct=clnk&amp;gl=il

bronsa15:09:35

yes, it creates an anonymous type, which is not a record

bronsa15:09:44

but it doesn't extend any concrete classes, nor records

bronsa15:09:59

if you want a non-anonymous reify, that's more or less deftype

bronsa15:09:08

modulo the IObj metadata support

Yehonathan Sharvit15:09:13

Is there a way to use deftype and provide a “base” type and extend it (like with reify)?

bronsa15:09:24

reify can't extend a base type

bronsa15:09:37

reify can only implement interfaces/protocols

bronsa15:09:09

deftype can't either, only proxy and genclass can extend base classes

ghadi15:09:12

no concrete derivation, by design

Alex Miller (Clojure team)15:09:42

which is also discussed in that same page you linked above

Alex Miller (Clojure team)15:09:05

"Concrete derivation is bad" to quote directly

simple_smile 4
manutter5115:09:45

@viebel Maybe you should describe the bigger problem you’re trying to solve by extending a base type?

Yehonathan Sharvit15:09:12

I remember that once I used something (maybe in clojurescript) that allows to extend a record

bronsa15:09:38

you may be thinking of specify, which is a clojurescript only construct

bronsa15:09:52

it doesn't exist in clojure

Yehonathan Sharvit15:09:10

Is there a good reason for that diff between clj and cljs?

bronsa15:09:24

specify doesnt extend a record either, it provides additional implementations to a particular instance of a type IIRC, and in clojure we can do something similar to specify now with extend-via-meta in protocols

Yehonathan Sharvit15:09:16

In cljs, there is specify! and specify, the latter doesn’t mutate the base instance (it clones it).

bronsa15:09:53

yes, neither extends a record

bronsa15:09:57

the record is the type

bronsa15:09:08

both variants of specify extend the instance of that type

Yehonathan Sharvit15:09:37

important clarification. Thanks

bronsa15:09:38

I don't know why clojurescript implemented specify

bronsa15:09:56

but it's not part of clojure's design, and it's not particularly easy to implement on the JVM

Alex Miller (Clojure team)15:09:04

to leverage the host capabilities, I believe

Alex Miller (Clojure team)15:09:18

although this is maybe a better question for #clojurescript or #cljs-dev

devn15:09:35

Hola, I'm struggling a bit to get zippers to do my bidding: https://gist.github.com/devn/61b3690f4d6e059303874d547c21f803 What did I mess up here? I've tried a bunch of variations and can't seem to figure out why the (set? l) branch in the loop doesn't get hit.

hiredman16:09:45

use tree-seq

devn16:09:33

@hiredman can I use that to construct a get-in/update-in-esque path like this?

hiredman16:09:36

but a recursive for will do it

hiredman16:09:22

l is a loc, which is the data structure a zipper uses to keep track of its traversal, so it is never a set

hiredman16:09:41

using into and empty to reconstruct seqs will reverse them

hiredman16:09:37

your child|branch? function only considers seqs to be branches if they have children

hiredman16:09:39

I seem to recall suggesting a recursive for to you for this kind of thing previously

hiredman16:09:43

((fn f [path parent-id item]
   (let [id (java.util.UUID/randomUUID)]
     (cons (assoc (dissoc item :children)
                  :id id
                  :path path
                  :parent parent-id)
           (for [child (:children item)
                 i (f (conj path (:name item))
                      id
                      child)]
             i))))
 []
 nil
 {:name "root",
  :description "root",
  :children
  [{:name "Foo",
    :description "foo",
    :children
    [{:name "Bar",
      :description "bar",}
     {:name "Baz",
      :description "Baz",
      :children [{:name "Qux",
                  :description "qux"}]}]}]})

hiredman16:09:58

you may also want to checkout a lens library (I haven't used any so I cannot recommend any), at least in theory with those the "path" you build will be directly usable to update sub values

devn16:09:12

@hiredman appreciate that, and yes, I seem to remember you recommending that approach previously as well 😄

devn16:09:42

@hiredman ok, just had a chance to run it, the only missing bit there is that some :children can be sets, which means the path would need to be constructed as ("root" {:name "foo" :description "foo" :children ...} ...) in some cases

devn16:09:57

and for vectors, it needs to be the index of the item in the vector for get-in/update-in reasons

devn18:09:01

(for anyone following along at home, I updated my gist and wound up getting my zipper-based solution working https://gist.github.com/devn/61b3690f4d6e059303874d547c21f803) One question I have in light of this is: Is there any particular design reason why update-in doesn't handle sets? For instance, the ability to do:

(update-in {:a {:b #{{:c :d}}}} [:a :b {:c :d}] assoc :e :f)

Alex Miller (Clojure team)18:09:42

update-in is for "associative structures"

Alex Miller (Clojure team)18:09:33

and inherently leans on assoc

MatthewLisp22:09:52

Hey guys, i'm making a guide to people who already do web development and want to have a head start in clojure

seancorfield23:09:15

Ring isn't an HTTP server. What you're bringing there is Jetty as the HTTP server.

MatthewLisp23:09:03

Thanks, i'll fix this 😅

seancorfield23:09:57

Given what you cover in that, I'd say input validation is probably the next logical step but probably ought to be "part 2" rather than making "part 1" any longer...?

👍 4
MatthewLisp23:09:35

That's cool, i'll break this in two parts (or even more if i feel adding more content) thanks for the feedback

MatthewLisp23:09:40

@U04V70XH6 could i describe Ring as an API for HTTP Server ? the description used on their github is "Clojure HTTP server abstraction "

seancorfield23:09:24

Yeah, API is a good way to describe it. The readme confirms that "By abstracting the details of HTTP into a simple, unified API, Ring allows web applications to be constructed of modular components that can be shared among a variety of applications, web servers, and web frameworks." and you can use Ring with http-kit or Jetty or Immutant or...

seancorfield23:09:39

We have apps that select Jetty or http-kit dynamically at startup -- and only the "start web server" logic cares: the entire rest of the app is unchanged by that decision (and I've tested that also works with Immutant, which can be used as a library the same way).

MatthewLisp23:09:31

Awesome, good to know, i'll mess around with http-kit later, won't put those info in this guide because i want to avoid complexity and more stuff that a newcomer would have to deal with, but surely this is nice to know, thanks again!

MatthewLisp23:09:35

Redacted into this: "Remember that the Ring library talks with a web server under the hood, in our case, the web server that we will use is [Jetty](https://www.eclipse.org/jetty/), because ring already has an adapter for jetty written and ready to use for us."

4
MatthewLisp22:09:29

I want to know if i should mention data input validation or this is out of the subject of my guide

MatthewLisp22:09:47

i would talk about input validation using Spec

MatthewLisp22:09:23

a quick glance on the draft is enough to know what i am presenting on this guide

fabrao22:09:51

Hello all, what happen with lein repl with clojure 1.10.1? The repl is starting in 1 second with cider, is that correct?

seancorfield23:09:26

@fabrao What do you think has changed from previous versions of Clojure with lein repl and/or CIDER?

fabrao23:09:36

I think the way of loading the stuffs in memory

seancorfield23:09:36

Can you be a bit more specific? And also which version of Clojure are you comparing this with? I can't think of anything that changed in Clojure. I believe CIDER's default middleware changed to be lazily loaded which may well improve startup time.

hiredman23:09:10

my guess is you have a user.clj file and you upgraded to a java version where it has the performance regression for code execute when running static inits

fabrao23:09:11

from 1.10.0 to 1.10.1

lilactown23:09:22

did you change JDK version?

hiredman23:09:47

oh, sorry, I think 1.10.1 is just the work around for that performance issue, so likely not it

fabrao23:09:57

I did update in JDK version yes

hiredman23:09:32

ah, nope, no work around for that yet

fabrao23:09:34

I´m asking this because before it started in 10-20 seconds

hiredman23:09:06

you should try again with the older jdk version if you can

fabrao23:09:13

I did update JDK and clojure

lilactown23:09:27

JDK 11+ has a perf problem when loading things in user.clj

seancorfield23:09:30

1.10.1 is starting faster for you -- so that's the workaround described in https://github.com/clojure/clojure/blob/master/changes.md

fabrao23:09:04

yes, I read this, but 10-20 times faster?

seancorfield23:09:09

If it was 10-20 seconds before, on 1.10.0, then you probably hit that user.clj loading issue yes.

seancorfield23:09:41

Did you also update CIDER? (see my comment above about it switching to lazy loading middleware).

fabrao23:09:55

yes, I did update CIDER too

fabrao23:09:18

well, this is a HUGE performance increase, I´m very happy with result, I even thougth to buy Mac to speed up the stuffs

hiredman23:09:21

so basically it could be a lot of things

seancorfield23:09:34

It's always better to update things one at a time and then you'll know exactly what caused any observable change.

seancorfield23:09:14

Updating multiple parts of your tool chain at once is ... an exercise for the, er, brave 🙂

fabrao23:09:46

yes, I did not update some stuffs fearing breaking some, and I asked you just about this because it was breaking after update some libs

skuttleman23:09:32

Why isn't there a ssecond? I've never been more disappointed in my life.

😆 4
andy.fingerhut23:09:46

Why do you think there isn't?

andy.fingerhut23:09:27

Wait, ssecond or second?

seancorfield23:09:13

@skuttleman What would ssecond do? (second (second x)) ?

skuttleman23:09:53

Yes. Just like ffirst or nnext, only seconder.

seancorfield23:09:51

I knew about the various first/`next` combo functions but never actually noticed these two docstrings were identical:

user=> (doc second)
-------------------------
clojure.core/second
([x])
  Same as (first (next x))
nil
user=> (doc fnext)
-------------------------
clojure.core/fnext
([x])
  Same as (first (next x))
nil
user=> 

seancorfield23:09:19

So I guess ssecond would be fnfnext 🙂 🙂 and Clojure <> Lisp so we don't go down the caddadr path...

4
seancorfield23:09:00

I suspect the various first/`next` combos all got in before the API was really being thought about? It would be interesting to hear from Stu or Rich on that...

andy.fingerhut23:09:06

ffirst and nnext are both actually used in clojure.core, so likely Rich considered them general purpose enough to include them in the API.

andy.fingerhut23:09:42

second is used in clojure.core, but not fnext

ghadi23:09:59

There is a great Sasha Baron Cohen interview about 15 years old where he asks some prominent financial expert why there isn't an $87.21 dollar bill

ghadi23:09:07

The expert asks him how he would pay if the bill was $87.22

ghadi23:09:37

He of course responds, "I'd pay with the $87.22 bill"

ghadi23:09:05

That's why there isn't an ssecond

4
👏 4