This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2022-08-04
Channels
- # announcements (5)
- # aws (11)
- # babashka (15)
- # beginners (101)
- # biff (14)
- # calva (45)
- # clj-kondo (18)
- # cljs-dev (5)
- # clojure (178)
- # clojure-austin (5)
- # clojure-europe (8)
- # clojure-france (1)
- # clojure-nl (12)
- # clojure-norway (6)
- # clojure-spec (4)
- # clojure-uk (1)
- # clojurescript (13)
- # community-development (2)
- # conjure (6)
- # cursive (8)
- # datahike (1)
- # datalevin (3)
- # datascript (36)
- # datomic (6)
- # emacs (2)
- # etaoin (2)
- # fulcro (5)
- # graalvm (6)
- # gratitude (3)
- # introduce-yourself (1)
- # jobs-discuss (1)
- # lsp (19)
- # malli (4)
- # nbb (11)
- # off-topic (4)
- # other-languages (1)
- # pathom (19)
- # pedestal (1)
- # shadow-cljs (22)
- # spacemacs (16)
- # tools-deps (31)
- # vim (7)
I am learning clojure from couple of weeks and doing some exercises, one of them is developing 2048 like dynamic game where board can be 4*4 or 3*3 or 8*8 and win-num is 2048, 4096 etc, i need below help How to convert [1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16] to ([ 1 5 9 13 ] [ 2 6 10 14 ] [ 3 7 11 15 ] [ 4 8 12 16 ]) values can be anything Currently is doing this (list (vec (take-nth 4 input-vec)) (vec (take-nth 4 (drop 1 input-vec))) (vec (take-nth 4 (drop 2 input-vec))) (vec (take-nth 4 (drop 3 input-vec)))) I want something genetic where i can convert [64 values] to (8 * [8 Values]) etc
(->> [1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16]
(partition 4)
(apply map vector))
=> ([1 5 9 13] [2 6 10 14] [3 7 11 15] [4 8 12 16])
Thanks (defn get-columns [game-board] (let [width (Math/sqrt (count game-board))] (println width) (->> (vec game-board) (partition width) (apply map vector)) )) (get-columns [1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16]) => #function[clojure.core/map/fn--5880] what am doing wrong here, how to get values instead of map-fn
You can't partition by double, the width is 4.0
. (The result will be ()
and (apply map vector ())
returns transducer.)
I have created my first program in clojure -> 2048 game, Any feedback will be helpful https://github.com/shravankgl/clojure-practice/tree/main/clojure-2408 Any other example i can try to improve, kindly let me know
Your code:
(defn get-zero-indicies
"get list of all indicies containing value 0"
[game-board]
(map first
(filter #(= (second %) 0)
(map-indexed vector game-board))))
Reviewed:
(defn get-zero-indicies
"get list of all indicies containing value 0"
[game-board]
(->> (map-indexed vector game-board)
(filter (fn [[_ v]] (zero? v)))
(map first)))
or even better:
(defn get-zero-indicies
"get list of all indicies containing value 0"
[game-board]
(keep-indexed (fn [i x] (when (zero? x) i)) game-board))
Your code:
(defn get-columns [game-board]
(let [width (int (Math/sqrt (count game-board)))]
(vec (apply map vector (partition width game-board))))
)
Reviewed:
(defn get-columns [game-board]
(let [width (int (Math/sqrt (count game-board)))]
(->> (partition width game-board)
(apply map vector)
vec)))
draw-board
- put (println row)
on the next line
move-cells
- put each let
variable on the new line and use only one let
execute
- use condp
, play-2048
- (* total-cells)
is strange, I think you wanted (* width width)
here
Is this really the expected result?
(->> (range 16)
(move-left))
=> (1 2 3 0 4 5 6 7 8 9 10 11 12 13 14 15)
@U03T0J7DF88 , I'm curious what you are using to keep your parens/brackets balanced? I only ask because the formatting of some of your functions/expressions might be considered a bit unidiomatic as we usually use the shape of things to help us see the flow. For example, when seeing a function like this:
(defn pick-random-empty-cell
"get a random 0 value cell"
[game-board]
(if (= (apply min game-board) 0)
(rand-nth (get-zero-indicies game-board))
-1))
I thought you had an error because of the way it's formatted. I thought your if
expression would just be discarded but it turns out your parens are balanced correctly. But normally I would expect to see the function look like:
(defn pick-random-empty-cell
"get a random 0 value cell"
[game-board]
(if (= (apply min game-board) 0)
(rand-nth (get-zero-indicies game-board))
-1))
It's a subtle difference but if you aren't using a structural editing tool (like paredit, parinfer, etc) I fear that manually balancing your parens while also formatting like this might lead to some unexpected errors and behaviors. I hope I'm making sense here and not just confusing you. There are also autoformatting tools like cljfmt
, which you can also use through clojure-lsp
, but I don't want to overwhelm you as setting up all the (great) tools we have and getting them working together can be a bit daunting.@U9J50BY4C thanks for the feedback, i was not using any formatting tools, just did the code in vscode without any tools. Now i have installed paredit and will update my code for more readablility. I did face unexpected errors and i am still not fully comfortable with repl as past decade i am used to debugging. Anything tools available for debugging along with repl.
@U01RL1YV4P7 Thanks for the feedback
This point is not clear for me
move-cells
- put each let
variable on the new line and use only one let
can you explain further
move-left
is the expected behaviour to convert
(4 4 0 2)
(2 0 0 0)
(0 0 0 2)
(0 0 0 0)
to
(8 2 0 0)
(2 0 0 0)
(2 0 0 0)
(0 0 2 0)
VS Code now has a great Clojure option called https://calva.io/. I highly recommend getting that installed and play around with it. That'll really help you start seeing the amazing benefits of an editor connected Clojure repl. The folks in the #calva channel will help you with any questions that come up.
Calva includes a debugger too. I'm not too familiar with the debugging options (and I don't use VS Code myself) so I've been playing around with this debugger I just discovered: https://clojurians.slack.com/archives/C06MAR553/p1657736395365869
Recent presentation on that debugger: https://www.youtube.com/watch?v=A3AzlqNwUXc&list=WL&index=6
But tbh I would just focus on Calva and getting familiar with that before taking on too many tools. The cool thing is, if I'm not mistaken, Calva is going to come with the LSP, linter, debugger and formatting capabilities all built in for you.
@U03T0J7DF88 Ok, your move-cells
:
(defn move-cells [arr]
(let [non-zero (filter pos? arr) width (count arr)]
(let [add-similar (add-pairs non-zero)]
(concat add-similar (repeat (- width (count add-similar)) 0)))))
Reviewed (I didn't check functionality, just the way code is written):
(defn move-cells [arr]
(let [non-zero (filter pos? arr)
width (count arr)
add-similar (add-pairs non-zero)]
(concat add-similar (repeat (- width (count add-similar)) 0))))
@U01RL1YV4P7 @U9J50BY4C The code is running fine when i do "lein run" While i am trying to create jar and execute "lein uberjar" i am getting this exception, kindly help clojure/git/clojure-practice-main/clojure-2408$ java -jar target/uberjar/clojure-2408-0.1.0-SNAPSHOT.jar Exception in thread "main" java.lang.NoClassDefFoundError: clojure/lang/Var at clojure_2408.core.<clinit>(Unknown Source) Caused by: java.lang.ClassNotFoundException: clojure.lang.Var at http://java.net.URLClassLoader.findClass(URLClassLoader.java:387) at java.lang.ClassLoader.loadClass(ClassLoader.java:418) at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:352) at java.lang.ClassLoader.loadClass(ClassLoader.java:351)
Your execute
function looks like a map to me. So you could write something like
(def game-keys {"w" move-up
"a" move-left
"s" move-down
"d" move-right})
(defn collect-user-input-and-move [game-board]
(let [input (read-line)]
(if-let [move (game-keys input)]
(move game-board)
(do
(println "invalid input")
game-board))))
to look up the movement function and apply it to the game-board. This would make it easier to change the keys (for example) which was the first thing I tried to do when I started running your code (w/a/s/d are not near each other on my keyboard)I'm also not such a fan of the way the behaviour of the game is coupled to the mechanics of collecting user input. You have a play-next
function which asks for user input using read-line
, plays the move and draws the board. This makes it difficult to control from the repl or implement an AI player. I'd like to be able to write a rich comment to play around with the game at the repl and test the code, maybe something like
(comment
(-> (initialise-board 4 2048)
add-cell
(game-step move-down)
(game-step move-left)
(game-step move-down)
print-board)
)
and see what state the game is in. I do this all the time in codebases I work in, and sometimes commit them as examples of how code works. In general more functional code is easier to do this with. The more state you have to deal with the harder it is to work with at the repl.I think breaking the code into more delineated layers would help. I think you have some board level operations like get-rows
and get-columns
, some game level ops like add-cell
and the move-*
fns, some player level ops like collect-user-input
(or even a generate-move
if you implemented a automated player) and some game mechanics like printing the board and going round the loop. I think it would be easier to work with if you separated the layers a little more. That aside, generally what you've written is good and with a little tidying as others have mentioned seems like a great start to your Clojure journey ;)
I will apply all the comments over weekend All the responses are just motivating me
I hope you don't mind, but I've had a bit of a play and rejigged your code a bit here: https://gist.github.com/l0st3d/d9e53f3d79d4acdf560f6031c65d0275 ... I'm not suggesting that what I've done is distinctly better than what you've done (I've modelled the board differently for example), just that this made more sense to my brain 😉 ... feel free to compare and contrast and tell me where I've done something stupid ... cos I almost certainly have 😉
Sure @U0P0TMEFJ i will check it out, I am not able to execute uberjar getting noclassdeffound error, do you have any idea on this
if you look in the target dir, there will be 2 jars. One is just your code, and the other is the uberjar. You need to run that one
java -jar /var/home/ed/dev/l0st3d/clojure-practice/clojure-2408/target/uberjar/clojure-2408-0.1.0-SNAPSHOT-standalone.jar
on my machine.the one with -standalone
in the name is an uberjar which has all the dependencies in it - I think that error is from trying to run the one without the dependencies packaged into it.
(defproject blabla "1.2.3" ...)
Is there some standard way to print Leiningen project version in the console? I looked at the help
output and found nothing... What I want is something like:
$ lein info --version blabla
1.2.3
You want this information for a scenario where you have the code locally and from the code’s directory you want to print its version information?
Thank you for the answer. Now need to figure out how to execute it in the one-liner form :thinking_face:
At the very least you can throw that into a namespace and you can call a main function which returns that
I think here is the answer: https://github.com/kumarshantanu/lein-exec
Could someone explain to me this beahvior? I’m using Clojure version 1.10.3
the behavior varies based on whether the data is seq?
- here it is not in the first example but is in the second
if seq, then the input is poured into a map to allow for further map destructuring
but in both cases, you are assuming things when the behavior is undocumented and undefined
for the seq case, you're seeing implementation details leak through for kwarg rest destructuring
okay. So the correct solution is probably to make sure you are destructuring a map if you are using map destructuring. 🙂
Hello everyone! I've been trying to use https://github.com/opencypher/cypher-for-gremlin/blob/master/translation/README.md in my project using lein, but I'm getting the following error:
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See for further details.
Exception in thread "main" Syntax error macroexpanding clojure.core/ns at (hello_world/handler.clj:1:1).
Call to clojure.core/ns did not conform to spec.
at clojure.lang.Compiler.checkSpecs(Compiler.java:6971)
at clojure.lang.Compiler.macroexpand1(Compiler.java:6987)
at clojure.lang.Compiler.macroexpand(Compiler.java:7074)
at clojure.lang.Compiler.eval(Compiler.java:7160)
at clojure.lang.Compiler.load(Compiler.java:7635)
at clojure.lang.RT.loadResourceScript(RT.java:381)
at clojure.lang.RT.loadResourceScript(RT.java:372)
at clojure.lang.RT.load(RT.java:463)
at clojure.lang.RT.load(RT.java:428)
at clojure.core$load$fn__6824.invoke(core.clj:6126)
at clojure.core$load.invokeStatic(core.clj:6125)
at clojure.core$load.doInvoke(core.clj:6109)
at clojure.lang.RestFn.invoke(RestFn.java:408)
at clojure.core$load_one.invokeStatic(core.clj:5908)
at clojure.core$load_one.invoke(core.clj:5903)
at clojure.core$load_lib$fn__6765.invoke(core.clj:5948)
at clojure.core$load_lib.invokeStatic(core.clj:5947)
at clojure.core$load_lib.doInvoke(core.clj:5928)
at clojure.lang.RestFn.applyTo(RestFn.java:142)
at clojure.core$apply.invokeStatic(core.clj:667)
at clojure.core$load_libs.invokeStatic(core.clj:5985)
at clojure.core$load_libs.doInvoke(core.clj:5969)
at clojure.lang.RestFn.applyTo(RestFn.java:137)
at clojure.core$apply.invokeStatic(core.clj:667)
at clojure.core$require.invokeStatic(core.clj:6007)
at clojure.core$require.doInvoke(core.clj:6007)
at clojure.lang.RestFn.invoke(RestFn.java:421)
at user$eval5.invokeStatic(form-init16536261567822868000.clj:1)
at user$eval5.invoke(form-init16536261567822868000.clj:1)
at clojure.lang.Compiler.eval(Compiler.java:7176)
at clojure.lang.Compiler.eval(Compiler.java:7165)
at clojure.lang.Compiler.load(Compiler.java:7635)
at clojure.lang.Compiler.loadFile(Compiler.java:7573)
at clojure.main$load_script.invokeStatic(main.clj:452)
at clojure.main$init_opt.invokeStatic(main.clj:454)
at clojure.main$init_opt.invoke(main.clj:454)
at clojure.main$initialize.invokeStatic(main.clj:485)
at clojure.main$null_opt.invokeStatic(main.clj:519)
at clojure.main$null_opt.invoke(main.clj:516)
at clojure.main$main.invokeStatic(main.clj:598)
at clojure.main$main.doInvoke(main.clj:561)
at clojure.lang.RestFn.applyTo(RestFn.java:137)
at clojure.lang.Var.applyTo(Var.java:705)
at clojure.main.main(main.java:37)
Caused by: clojure.lang.ExceptionInfo: Call to clojure.core/ns did not conform to spec. {:clojure.spec.alpha/problems [{:path [], :reason "Extra input", :pred (clojure.spec.alpha/cat :docstring (clojure.spec.alpha/? clojure.core/string?) :attr-map (clojure.spec.alpha/? clojure.core/map?) :ns-clauses :clojure.core.specs.alpha/ns-clauses), :val ((:require [compojure.core :refer :all] [org.opencypher.gremlin/translation :as translation] [compojure.route :as route] [ring.middleware.defaults :refer [wrap-defaults site-defaults]])), :via [:clojure.core.specs.alpha/ns-form], :in [1]}], :clojure.spec.alpha/spec #object[clojure.spec.alpha$regex_spec_impl$reify__2509 0x6413eeb7 "clojure.spec.alpha$regex_spec_impl$reify__2509@6413eeb7"], :clojure.spec.alpha/value (hello-world.handler (:require [compojure.core :refer :all] [org.opencypher.gremlin/translation :as translation] [compojure.route :as route] [ring.middleware.defaults :refer [wrap-defaults site-defaults]])), :clojure.spec.alpha/args (hello-world.handler (:require [compojure.core :refer :all] [org.opencypher.gremlin/translation :as translation] [compojure.route :as route] [ring.middleware.defaults :refer [wrap-defaults site-defaults]]))}
at clojure.spec.alpha$macroexpand_check.invokeStatic(alpha.clj:705)
at clojure.spec.alpha$macroexpand_check.invoke(alpha.clj:697)
at clojure.lang.AFn.applyToHelper(AFn.java:156)
at clojure.lang.AFn.applyTo(AFn.java:144)
at clojure.lang.Var.applyTo(Var.java:705)
at clojure.lang.Compiler.checkSpecs(Compiler.java:6969)
... 43 more
Its a .jar at .m2/repository/org/opencypher/gremlin/translation/1.0.4/translation-1.0.4.jar
If I use with [org.opencypher.gremlin$translation :refer :all]
it throws
java.io.FileNotFoundException: Could not locate org/opencypher/gremlin$translation__init.class, org/opencypher/gremlin$translation.clj or org/opencypher/gremlin$translation.cljc on classpath.
I think that org.opencypher.gremlin/translation is a library, I added in the project as a dependency
@U03S85Q5P38 Coordinates do not match class names or namespaces.
The closest thing I can find, in the opencypher repo be org.opencypher.gremlin.translation.TranslationFacade
as a qualified class name and you would import that in Clojure like this:
(ns my.clojure.code
...
(:import (org.opencypher.gremlin.translation TranslationFacade)))
and then use the classname TranslationFacade
See https://github.com/opencypher/cypher-for-gremlin/blob/master/translation/src/main/java/org/opencypher/gremlin/translation/TranslationFacade.java for example
But it really does depend on what you are trying to do. Are you following some specific documentation / tutorial about this and trying to get it working in Clojure instead of Java/Scala?
yeah, you have to do that for clojure libs too. make issue requests if repos don't tell you what their namesspaces are in the readme
@U0LAJQLQ1 The Gremlin translation repo does show how to use it in its README. @U03S85Q5P38 is struggling to "translate" how to use a Java/Scala library into Clojure code I think (and not realizing that the library name -- coordinates -- rarely match the packages in the Java code / namespaces in the Clojure code).
(I'm out for a while but will check back in on this thread later if you're still stuck @U03S85Q5P38)
@U03S85Q5P38 are you able to get the classes imported in your ns?
doing java stuff in clojure isn't very easy. if you are already an expert with the libs, or are proficient in java, that helps a lot. if your editor can inspect objects, that is very helpful. also setting up your editor to use javadocs is good too.
if I'm using a template/stub that is written in Java, can I just toss it in my project folder and import
it like its a core Java library, or will I need to explicitly add it to my classpath
It will need to be compiled to a .class
file and that will need to be on the classpath.
Hi! don't want to start a fight or a hot take or anything like that, but is there a simple (I guess in the clojure sense) editor setup for clojure? What I mean by that is something that doesn't require too many pieces interacting with each other in surprising ways. For example, Calva is amazing for getting starter but I usually find that it brings too many new things into my vscode configuration, new keymappings, changes syntax highlighting, etc. I also tried conjure for nvim and at least in all the tutorials I found around it requires that you install many plugins and change many configurations to make it work. What I am looking for is something like a minimal extension that let me sends s-expression from my editor to be evaluated in my running repl. Does something like that exists?
Just running a repl in a terminal and copying and pasting from your editor works great
I think that is part of the problem too. Clojure for almost everything promotes the use of very decouple pieces that come together to form a solution. how ever for editors I still don't feel that's the case. I which I couldn't had to reset my muscle memory of 10s of years programming in the same enviroment just to fully enjoy clojure. I which those were ortogonal in a way.
If you use IntelliJ, Cursive I would say is very much following the IntelliJ patterns, so it won't feel any different, and it is all self-contained, unlike Calva which relies on orchard, lsp, kondo, etc.
I think https://gitlab.com/clj-editors/clover might be a smaller scope solution for VS Code but I personally have no experience with it.
I guess the first question should be: what is your favorite editor? What do you have the most muscle memory with?
Then we can suggest the simplest add-on that provides some Clojure interaction.
For vim I've heard people say good thing about https://github.com/liquidz/vim-iced but never used it.
You could also try either Spacemacs or Doom Emacs with inf-clojure, both have Vim default keybindings and modal behavior
just took a look at vim-iced, seem a bit more minimal than conjure which is nice. I guess another option will be to write a minimal extension for vscode that sends stuff to a socket repl, no inline evaluation, just very basic stuff.
If you're using VS Code and want something very minimal, I can recommend Clover. I used that daily for a long time, before switching to Calva, but you have to start a Socket REPL instead of using nREPL -- Socket REPL is more minimal so that may suit you.
https://gitlab.com/clj-editors/clover/ -- it was originally here https://github.com/mauricioszabo/clover -- this was my VS Code / Clover setup https://github.com/seancorfield/vscode-calva-setup/tree/6a8450be5d32e4244faaa571826091ed4abf94f0 and this was my dot-clojure setup back then https://github.com/seancorfield/dot-clojure/tree/437b1e67cff2bb9cfbba053db49cc36cf2a5b841
There are specific channels for almost everything mentioned in this thread so feel free to drop into those and ask more Qs if you need to! #chlorine-clover #calva #conjure #neovim #spacemacs #inf-clojure and probably others.
If you're willing to give Sublime Text (presumably with Vim key bindings) a try, both https://github.com/tonsky/Clojure-Sublimed and https://tutkain.flowthing.me would fit your requirements, I think.
Already mentioned, but what you describe is precisely how I feel about Chlorine+Atom and Clover-VSCodium. Simple and clean and easy to understand.
• Sublime • Intellij The above are the only editors remaining that I believe could be called “easy”. Prior to Atom being sunset, I would have recommended that as well.
I recal seeing this recently : https://lambdaisland.com/episodes/ultimate-dev-setup ... which definitely demonstrates how easy it is to get basic tooling set up out of the small composable tools in quite a light hearted way 😉