Fork me on GitHub
#beginners
<
2020-09-11
>
Joel05:09:00

How do I sort a list based on an ordered sequence. For example [:low :medium :high], I want my list sorted so lows are first highs are last.

hiredman05:09:42

You turn the vector into a map of element to index, then sort-by with that map

metal 3
simongray10:09:49

clojure can be so elegant in its simplicity.

Joel05:09:31

ah so { :low 1 :medium 2 :high 3 }

3
Grigory Shepelev12:09:31

What the problem with my standalone jar?

Error: Could not find or load main class 
Caused by: java.lang.ClassNotFoundException: 
I'm a total newbie in devops-related stuff on java/clojure interop and that's my first uberjar attempt. Sorry for the questions that might be trivial

Alex Miller (Clojure team)12:09:05

the message is telling you that the jar does not contain genomics/app.class

Alex Miller (Clojure team)12:09:34

you can see inside the jar with jar tf whatever.jar - probably good to see what it includes

Alex Miller (Clojure team)12:09:56

you might need to add (:gen-class) to that namespace and aot compile it

Grigory Shepelev13:09:42

Yes. Guess that's the problem. Where should I put it?

(ns 
  (:require [genomics.gui :as gui]
            [cljfx.api :as fx]))

practicalli-johnny13:09:04

Just add :gen-class by itself if you are only calling http://genomics.app functions from the command line

(ns 
  (:gen-class)
  (:require [genomics.gui :as gui]
            [cljfx.api :as fx]))
I do this with the clojure apps I run, e.g https://practicalli.github.io/clojure-webapps/projects/banking-on-clojure/application-server-configuration.html

Grigory Shepelev13:09:59

before :require?

Grigory Shepelev13:09:37

I added :gen-class but it still shows the same exception

Alex Miller (Clojure team)13:09:40

can be either before or after require

Alex Miller (Clojure team)13:09:48

and then you need to make sure you aot compile the code

Alex Miller (Clojure team)13:09:05

if you're using leiningen, adding :aot :all should do it

Grigory Shepelev14:09:49

It's not helping. Lein just hangs. It's probably libriary-specific problem. I asked in #cljfx but still no answer

Alex Miller (Clojure team)14:09:49

if it's hanging, what's probably happening is that you have top-level defs in your code that are being run during compilation

Alex Miller (Clojure team)14:09:59

which is generally a bad idea

Alex Miller (Clojure team)14:09:15

but that's what I'd look for

Grigory Shepelev14:09:39

I don't know what's ment by "top-level expression". Why it runs in lein run?

Alex Miller (Clojure team)14:09:23

compilation of ":all" may not happen in the same load order as your app

Alex Miller (Clojure team)14:09:38

I'm flying blind here, just making my best guess

alpox14:09:11

Hi all! There is a rather small Website I wanted to try Clojure on but got stuck early. I use the Luminus Template with HugSQL for it - the database behind is (must be) MySQL I will need all text of the entities to be multi-lingual and wondered what would be the best way to treat it with HugSQL. One way would be to write out the table-spanning multi-lingual queries for every entity but that would kind of be a huge verbose bunch of SQL. I wondered if someone already made a good setup / has some ideas for how to structure those queries with HugSQL. I'm using a single translation table together with a single language table but I'd be happy to change the table layout if it makes the usage better

nick21:09:55

Is there a specific need why those "entities" need to be stored in MySQL? Perhaps it all can be stored in a simple .edn file? It can be updated by non-techy people, it is easy to validate its form and switch between languages.

alpox22:09:14

The reason for the translations to be stored in MySQL is for that they can be edited through the website. An edn would be possiblw if the backend would be hosted with a persistent storage attached which for this project wont be the case

stopa16:09:56

Hey team, curious question for you: What is clojure’s thought on “data abstraction”, as in: say you use a map to represent some data-structure — user You would use functions to operate on the user data structure like (name user) (address user) , rather then keying directly: (:name user). The main reason being: could change the underlying implementation of user (i.e from map to list or something) (I see this pattern a lot in the older lisps: norvig talked about it paradigms of ai programming, and sicp mentions it) I see the benefit, but at least for clojure some of these function seem unnecessary. What is the clojurists way when it comes to this?

delaguardo17:09:20

sometime it is handy to think about data structure (maps to be precise) as about functions (let [user {:name "Foo" :address "address"}] (user :name))

Alex Miller (Clojure team)17:09:19

the whole benefit of maps and being able to use keywords as functions directly is that we don't need to make another layer, so my pov is that that kind of "abstraction" is not abstraction, it's indirection and it's downsides are bigger than its benefits

❤️ 9
Alex Miller (Clojure team)17:09:53

don't make functions that duplicate what you already have

👍 9
seancorfield17:09:39

We've used it at work only where we are migrating from mixed case keys to lowercase keys or to namespace-qualified keys and some code has to be able to hand "both" while we are transitioning, but I would not recommend it as a normal mode of operation.

👀 9
👍 3
didibus23:09:37

Ya, I remember at some point I was thinking, should I put all my keywords behind a Var. Like:

(def name :name)
And then do (name map), just so I could change this easily if the key changed. But never bothered with it lol. I feel its only a problem the one time where you are like, damn we have a typo in the key, I'm OCD and want to fix the typo.

didibus23:09:02

It would be pretty cool though if ILookup could be extended by metadata. Then you could like change your Map or whatever and just add some meta adapter for :old to :new

didibus23:09:11

Hum... or I guess in theory, this might get funky lol. But what if you could have a self-referential map where the key: :old pointed to the value of the key :new in the same map :thinking_face:

Ross Chapman22:09:09

The distinction that Clojure makes between a string — "A" — and a literal character — \A — is pretty awesome. This seems useful.

andy.fingerhut01:09:18

Inherited from the similar distinction that the JVM makes between those two types, in this case.

andy.fingerhut01:09:57

ClojureScript does not have this distinction, I would guess because JavaScript does not have a character type, only strings.

Ross Chapman01:09:11

ohhh that makes sense

Ross Chapman01:09:32

Yeah it’s a little weird because I’m learning Clojure on the JVM even though I’m coming from JS

andy.fingerhut01:09:00

[18:08:59] $ clj
Clojure 1.10.1
user=> (map identity "abcdef")
(\a \b \c \d \e \f)
user=> ^D

$ clj -Sdeps "{:deps {org.clojure/clojurescript {:mvn/version \"1.10.597\"}}}" -m cljs.main --repl-env node
ClojureScript 1.10.597
cljs.user=> (map identity "abcdef")
("a" "b" "c" "d" "e" "f")

Ross Chapman01:09:36

Programming is fun

Mno11:09:16

It sure is

didibus22:09:48

@stopachka The function (:foo m) is already a data abstraction, because it is implemented not for PersistentMap, but for anything that implements ILookup. And Associative implements ILookup, and that's also an abstraction which PersistentMap implements. So you have 2 layers of data asbtraction happening when you call (:foo m) already 😛

👍 3
💯 3
stopa22:09:23

Gotcha, thanks for the clarity folks!

didibus22:09:40

Ya, it means in theory, you could create a new data-structure and have keyword as function work on them to retrieve some associated value. Though since Clojure is implemented in terms of Java interfaces and not Clojure Protocol, you cannot extend it yourself, you need to modify the source code of the data-structure itself, so you can't for example add support for it to PersistentLists or sets or strings, etc.

didibus22:09:52

But I think fundamentally, what you're reading about data abstraction has some other concept in it which is kind of different, which implies creating custom user defined types, such as a User type. This gets complicated, and I don't know if I should venture about this in "beginner" but here goes 😛 {:name "John" :email ""} is a Map which contains information about a user. We did not create a "User" abstraction here. We just put information about some user in an existing reusable abstraction called a Map. This means that if you want to manipulate the information about the user, you can use all the existing Map functions to do so. You do not need any new functions. This is a common pattern in Clojure. We commit to the way we decided to represent information and just choose to use this directly. It does mean that if you decide to represent the information in a different way later, you break all usage of it. So if you change :name to :first-name you broke a bunch of code. Similarly, if you choose to change the model to a list like so: [:user "John" :email ""] you also broke all the code that was using the map directly. You can decide yourself if you mind this possibility or don't care. I think most people in Clojure wouldn't care, because in practice, you almost never change the structure 😛 So you can think of it as, maybe it takes you a little longer to refactor in the rare case you would need to change it, but you saved yourself a bunch of time not bothering with some half-baked User abstraction that most of the time will just be more inconvenient to work with than a Map/List/Set would be. In a language with mutable data-structures this would be a huge risk! Because you need to protect the usage of the data from uncoordinated concurrent modification. So when data is mutable, you would definitely want to protect access behind a function. And Clojure enforces that if you create a deftype for example, which provide mutable structures, like it forces you to always have data accessors and prevents you from changing the mutable data directly. Even with simple structure, like a single mutable field, Clojure forces you to use some data abstraction to change it like with atom where you can only do atomic changes to it.

jaihindhreddy05:09:14

Just gonna leave this here. It's too great of an opportunity to pass up 😛: https://www.youtube.com/watch?v=aSEQfqNYNAc