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.
You turn the vector into a map of element to index, then sort-by with that map
clojure can be so elegant in its simplicity.
ah so { :low 1 :medium 2 :high 3 }
What the problem with my standalone jar?
Error: Could not find or load main class <http://genomics.app|genomics.app>
Caused by: java.lang.ClassNotFoundException: <http://genomics.app|genomics.app>
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 trivialthe message is telling you that the jar does not contain genomics/app.class
you can see inside the jar with jar tf whatever.jar
- probably good to see what it includes
you might need to add (:gen-class) to that namespace and aot compile it
Yes. Guess that's the problem. Where should I put it?
(ns <http://genomics.app|genomics.app>
(:require [genomics.gui :as gui]
[cljfx.api :as fx]))
before :require?
I added :gen-class but it still shows the same exception
can be either before or after require
and then you need to make sure you aot compile the code
if you're using leiningen, adding :aot :all
should do it
Just add :gen-class by itself if you are only calling http://genomics.app functions from the command line
(ns <http://genomics.app|genomics.app>
(: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.htmlIt's not helping. Lein just hangs. It's probably libriary-specific problem. I asked in #cljfx but still no answer
if it's hanging, what's probably happening is that you have top-level defs in your code that are being run during compilation
which is generally a bad idea
but that's what I'd look for
I don't know what's ment by "top-level expression". Why it runs in lein run?
perfectly
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
compilation of ":all" may not happen in the same load order as your app
I'm flying blind here, just making my best guess
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?
sometime it is handy to think about data structure (maps to be precise) as about functions
(let [user {:name "Foo" :address "address"}]
(user :name))
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
don't make functions that duplicate what you already have
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.
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.
The distinction that Clojure makes between a string β "A"
β and a literal character β \A
β is pretty awesome. This seems useful.
It sure is
@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 π
Gotcha, thanks for the clarity folks!
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.
https://github.com/arohner/clj-wallhack/blob/master/src/wall/hack.clj#L38-L55 is an example of a custom ILookup
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
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 "<mailto:john@gmail.com|john@gmail.com>"}
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 "<mailto:john@gmail.com|john@gmail.com>"]
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.
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.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
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: