This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2020-04-25
Channels
- # announcements (2)
- # architecture (7)
- # aws (1)
- # babashka (105)
- # beginners (88)
- # braveandtrue (2)
- # calva (9)
- # cider (18)
- # cljs-dev (265)
- # cljsrn (22)
- # clojure (138)
- # clojure-argentina (3)
- # clojure-austin (1)
- # clojure-france (14)
- # clojure-italy (6)
- # clojure-uk (8)
- # clojurescript (283)
- # community-development (4)
- # conjure (11)
- # datomic (43)
- # docker (12)
- # duct (16)
- # emacs (1)
- # figwheel (1)
- # figwheel-main (27)
- # fulcro (10)
- # graalvm (6)
- # kaocha (4)
- # malli (9)
- # off-topic (13)
- # rdf (2)
- # reagent (12)
- # shadow-cljs (86)
- # spacemacs (1)
- # vrac (1)
how can i make a string of an expression bound in my namespace, including indentation and whitespace? i've taken a look at clojure.repl/source
which is close to what i need, but it my case i want to inject the expression into a hiccup template (as a string) at the time of evaluation.
I wouldn't say such a thing is impossible, but at least the Clojure reader does not preserve this information. I think it will preserve the starting line and column in the input file of some selected expressions, but not all.
There are other libraries that can read Clojure code and/or EDN data and preserve other things that the Clojure reader does not.
hmm. it looks like i can leverage pprint for formatting. in which case, is it possible to read a def'ed expression as a string?
(defn my-func [] 1)
(fn->str my-func)
=> "(defn my-func [] 1)"
any thoughts of learning clojure/functional programming before CS in uni? I am a highschool student and spend most of my programming time learning functional programming and clojure. I kinda fear that learning clojure and functional programming might mess me up for CS in uni, because I believe they are more based on lower level and imperative langauges. Any thoughts on this? (I hope this is a valid question for the beginners section)
i'm sure a lot has changed since i was at university, but one common theme of nearly all the languages i remember using was that they were strongly typed, which of course we don't see in Clojure. in my opinion it's worth learning any strongly typed language at a basic level just because they're unavoidable in the real world, and especially at uni. but focusing on Clojure certainly will not "mess you up" for a CS degree, and in fact you might find yourself writing better object oriented code with reduced state because of your exposure to Clojure / LISP.
oh I see so basically what you are saying is that by learning functional lisp programming, I would actually be able to write better OOp code
I think it's a great idea to learn Clojure before a CS program. as @joshkh said, it'll improve your understanding of coding principles. Lower level stuff you can pick up easily. Basically, you need to name every drawer where you keep something, and different things can manipulate the drawers without other things knowing. This is unsatisfactory for sanity. However, it is the decades-long norm in CS. I think it's easy to pick up this habit later, and I don't know why you would want to 😄 If you are doing low-level device programming, sometimes you have not the clock cycles to spare, but Church-Turing should give you confidence that anything you can do with a lisp you can do with imperative and vice versa, it's just taking into account psychic peace that draws a clear victory line for me.
Chris, my first serious programming instruction was done in Scheme in college, and it was wonderful. It expanded my mind and exposed me to new things, and the following semester I was writing linux networking code in C! I also have a friend who learned programming with Lisp in high school, and it was a formative experience for him, too. You are learning cool things and they’re fun! There’s NO downside to that AT ALL. 🙂 I have never ever ever met anyone who ever said “I regret having fun learning a cool unusual programming thing”
@U010GL90FN0 Thxs for your answer! I already thought that lisp is such a cool language, and now I'll just keep going 😄
For what it's worth, I help teach courses in a top-ten CS program, and we teach scheme as well. LISPs are nice when saying things about the mathematical properties of computer programs
Hmm. I heard that a lot. Of how lisp is good for mathematical representation, but I didn't quite get it because, when you write inside parentheses and with prefix notation, it doesn't look like the conventional mathematical notations we usually see. I know notation and the styling isn't rly anything but would it be ok for you explain that a little bit? Thxs @U0120B5AN2W
Sure. The notation doesn't really matter. It's more because of the properties of referential integrity (https://en.wikipedia.org/wiki/Referential_transparency) and because you can prove things about them using mathematical induction.
It's hard to prove things about programs where the state varies all of the time.
Oh I see. So basically immutabilty, pure functions, and the things you talked about mathematical induction and referential transparency makes this better clojure better than other languages with mutable data types
I don’t think it will mess you up. If you want to get a CS degree, you should learn more than one style of programming, even if not all styles are equally used or productive
It may make you annoyed at having to do projects in language styles that you do not prefer, but hopefully you can view those as part of the learning process
Hello all. would like to use https://github.com/weavejester/ragtime with clj and not Leiningen. How can I set it up? Should I write a lib? or can database configs go into the deps.edn?
are you familiar with deps.edn
? if so then you can include ragtime as a dependency and then require it from your code, just as you would with a lein based project.
{:paths ["src/clj" "resources"]
:deps {org.clojure/clojure {:mvn/version "1.10.1"}
ragtime {:mvn/version "0.8.0"}}}
Just like with Leiningen!
You just have to call ragtime.repl/migrate
with your configuration.
https://github.com/weavejester/ragtime/wiki/Leiningen-Integration
> database configs go into the deps.edn
You can load the config on the function that's being invoked, just like the Lein integration example.
> Should I write a lib?
IIUC, no. You may have to write a ns
to invoke it with (e.g.) cli -m my.migration
@U1UQEM078 I am so new to clojure that I am probably tripping on something extremely simple. I am able to apply migrations in REPL:
Clojure 1.10.1
user=> (ns user (:require [ragtime.jdbc :as jdbc]))
nil
user=> (def config {:datastore (jdbc/sql-database {:connection-uri "jdbc:sqlite:resources/db.sqlite"}) :migrations (jdbc/load-resources "migrations")})
#'user/config
user=> (require '[ragtime.repl :as repl])
nil
user=> (repl/migrate config)
Applying 001-foo
nil
user=>
Yes, that's expected behaviour and essentially what you'll accomplish through the cli invocation
So my qustion is, to achieve zero argument migrate in REPL, where do I place the def
statements so that they are automatically sourced?
Oh, ok that makes sense, so when I am to do migrations I just call that. Thank you, not sure why I did not think of it.😂
NP! You can also create "task" namespaces and invoke those normally. clj -m namespace
will call whatever is in the ns' -main
$> echo "(ns example2) (def a 3) (defn -main [] (println a))" > src/example2.clj
$> clj -m example2
3
Hmm, that did not seem to work. It executed the file but did not enter the REPL. There is probably a way to execute a file and enter REPL.
I added a file migrations.clj
at the project root.
(ns user (:require [ragtime.jdbc :as jdbc] [ragtime.repl :as repl]))
(def config
{:datastore
¦(jdbc/sql-database {:connection-uri "jdbc:sqlite:resources/db.sqlite"})
¦:migrations (jdbc/load-resources "migrations")})
Then tried clj -m user
and it gave me the following:
Execution error (FileNotFoundException) at clojure.main/main (main.java:40).
Could not locate user__init.class, user.clj or user.cljc on classpath.
Full report at:
/tmp/clojure-5805258766426369068.edn
> It executed the file but did not enter the REPL.
That's expected. If you want to be in a REPL, you have to start one (with clj
or clj -r
)
$> clj
Clojure 1.10.1
user=> (require 'example2)
nil
user=> (example2/-main)
3
nil
user=>
> Could not locate user__init.class, user.clj or user.cljc on classpath.
That's also expected, since you've added the file at the project root and the default classpath is /src
Another issue you'll probably run into is that the filename has to match the namespace (due to java constraints). migrations.clj
should have (ns migrations)
Hmm, I want to be able to enter REPL and call migrate
and rollback
OK, so basically, I am trying to enter REPL with the following requirements and definitions applied:
(ns user (:require [ragtime.jdbc :as jdbc] [ragtime.repl :as repl]))
(def config
{:datastore
¦(jdbc/sql-database {:connection-uri "jdbc:sqlite:resources/db.sqlite"})
¦:migrations (jdbc/load-resources "migrations")})
$> clj -e "(require 'example2) (in-ns 'example2)" -r
#object[clojure.lang.Namespace 0x1917d90f "example2"]
example2=> (-main)
3
nil
Or, using the first script file (without a ns)
$> clj -e '(load-file "example.clj")' -r
3
user=> a
3
Hmm, does not seem to keep the configurations:
(ns migration (:require [ragtime.jdbc :as jdbc] [ragtime.repl :as repl]))
(def config
{:datastore
(jdbc/sql-database {:connection-uri "jdbc:sqlite:resources/db.sqlite"})
:migrations (jdbc/load-resources "migrations")})
[I] /home/sporty/clojure/dbt~> clj -e "(require 'migrate) (in-ns 'migrate)" -r
#object[clojure.lang.Namespace 0x51c959a4 "migrate"]
migrate=> (repl/migrate config)
Syntax error compiling at (REPL:1:1).
No such namespace: repl
migrate=>
For some reason, it does keep the config variable defined, nor are the require
statements are honored.
just chiming in 2 hours later, but i also find it useful to create aliases for tasks in deps,edn which you can run without having to specify file names: clj -A:migrate
@U1UQEM078 wow, that worked, thank you. I am from C++ world, so much new stuff to grasp that I am misspelling :(
@joshkh I have been lookng at the :aliases
and tried: :migrate {:main-opt ["-e" \"(require 'migrate) (in-ns 'migrate)\""]}}
So can C style escape sequences be used?
hmm, i don't know. i usually just create a namespace for each alias, and then i can leverage arguments from the command line. for example:
{:aliases {:deploy-to-aws {:main-opts ["-m" "myproject.deploy"]
:extra-deps {com.datomic/ion-dev {:mvn/version "0.9.251"}}}}}
and then a namespace with a main function
(ns myproject.deploy)
(defn -main [& [lambda-name]]
(infof "Pushing lambda to AWS: " lambda-name)
...)
and finally call it from the terminal
$ clj -Adeploy-to-aws send-email-lambda
aliases can provide a lot of flexibility when performing tasks programmaticallyand using that :`extra-deps` key let's you isolate dependencies (such as ragtime) that you don't necessarily want in your core code
@joshkh, that worked!, I just have to figure out how to pass a string in for up
and down
migrations, but I think I have the information to do it. Just need to put it together. Thank you for helping me through my first day as an aspiring clojerian.
I think it's a great idea to learn Clojure before a CS program. as @joshkh said, it'll improve your understanding of coding principles. Lower level stuff you can pick up easily. Basically, you need to name every drawer where you keep something, and different things can manipulate the drawers without other things knowing. This is unsatisfactory for sanity. However, it is the decades-long norm in CS. I think it's easy to pick up this habit later, and I don't know why you would want to 😄 If you are doing low-level device programming, sometimes you have not the clock cycles to spare, but Church-Turing should give you confidence that anything you can do with a lisp you can do with imperative and vice versa, it's just taking into account psychic peace that draws a clear victory line for me.
Hmm, does not seem to keep the configurations:
(ns migration (:require [ragtime.jdbc :as jdbc] [ragtime.repl :as repl]))
(def config
{:datastore
(jdbc/sql-database {:connection-uri "jdbc:sqlite:resources/db.sqlite"})
:migrations (jdbc/load-resources "migrations")})
[I] /home/sporty/clojure/dbt~> clj -e "(require 'migrate) (in-ns 'migrate)" -r
#object[clojure.lang.Namespace 0x51c959a4 "migrate"]
migrate=> (repl/migrate config)
Syntax error compiling at (REPL:1:1).
No such namespace: repl
migrate=>
Why does calling flatten
on a set or map return the empty list unlike when calling it on vectors and lists?
You can have a flatten that works on all collections by substituting sequential?
for coll?
in the source.
(defn flatten- [x] (filter (complement coll?) (rest (tree-seq coll? seq x))))
Hello everyone, I’m working on a basic Reagent project using just shadow-cljs. I’m using cider nrepl and VS Code Calva. On my main app file, I have a simple atom for toggle:
(ns alpha-journal.core
(:require
[reagent.core :as r]
[reagent.dom :as dom]))
(def toggled (r/atom false))
(defn app []
[:div {:class [(when true 'bg-red-500) 'h-screen]}
...
which is referenced in the app component.
However, when I used my repl and lookup any variables or functions, it gives me the value, but also gives me a warning:
alpha-journal.core=> @toggled
------ WARNING - :undeclared-var -----------------------------------------------
Resource: :1:2
Use of undeclared Var alpha-journal.core/toggled
--------------------------------------------------------------------------------
false
What does this warning mean? Why are my variables considered undeclared? How can I get fix this warning?
Thanks for all the help 🙂@U11BV7MTK I don’t think I did explicitly? My shadow-cljs.edn looks like this
{:deps true
:builds {:app {:target :browser
:output-dir "public/out"
:asset-path "/out"
:modules {:main {:init-fn alpha-journal.core/main}}
:devtools {:http-root "public"
:http-port 8020}}}}
and my startup log shows shadow-cljs - nREPL server started on port 59071
That is then the port I connected to via Calva@U11BV7MTK then in Calva I switched namespace to my main file:
cljs.user=> (ns alpha-journal.core)
Gotcha, thanks I’ll try that out now
@U11BV7MTK Thanks! that fixed it. Quick question, is there any particular reason why I have to use the delayed eval quote for my namespace:
(in-ns 'alpha-journal.core)
vs (in-ns alpha-journal.core)
?
Thanks for all the help once again
It’s not delayed eval. If you eval a random symbol it tries to look it up in the environment and errors if it’s not defined
The quote makes sure we are talking about the symbol rather than what that symbol resolves for
Got it, thanks for the clarification, helps clear up a lot about the use of quote in general 🙂
Why do I get?
[I] /home/sporty/clojure/dbt~> clj -Amigrate up
Applying 003-zet
Execution error (NullPointerException) at migrate/-main (migrate.clj:10).
null
Full report at:
/tmp/clojure-728581667734213604.edn
When I run the following file with the up
argument?
1 (ns migrate (:require [ragtime.jdbc :as jdbc] [ragtime.repl :as repl]))
2
3 (def config
4 {:datastore
5 ¦(jdbc/sql-database {:connection-uri "jdbc:sqlite:resources/db.sqlite"})
6 ¦:migrations (jdbc/load-resources "migrations")})
7
8 (defn -main [ arg ]
9 (case arg
10 ¦ "up" ((repl/migrate config))
11 ¦ "down" (repl/rollback config)))
Notice that I do not get this issue when the case
keyword is not used.Oops nevermind, it's hard to let go of C++ and realize that it is all data, below works.
8 (defn -main [ arg ]
9 ((case arg
10 ¦ "up" repl/migrate
11 ¦ "down" repl/rollback) config))
I'm trying to evaluate someone elses code which uses clojure.core.matrix. Line 3 attempts to set index 100 to 1 but fails. I'm guessing the functionality has changed, but I can't find the way to do it. How can you set the value of a vectorz
?
I am working my way thru the book, “Clojure for the Brave and True”. And I am stuck on a problem in chapter 4 (https://www.braveclojure.com/core-functions-in-depth/#A_Vampire_Data_Analysis_Program_for_the_FWPD). The problem is to convert a CSV string into a sequence of vectors and then into a sequence of maps. I am stuck in in mapify function. I dont understand where the ARGS for the PARAMS of its second anonymous function come from. The fifth line from the bottom of the code snippet pinpoints the parameters.
(ns fwpd.core)
;(def filename "suspects.csv")
;(slurp filename)
(def suspects "Edward Cullen,10\nBella Swan,0\nCharlie Swan,0\nJacob Black,
3\nCarlisle Cullen,6\n\n")
(defn parse
"Convert CSV into a seq of vecs, into rows of columns ([name num] [name num] ...)"
[string]
(map #(clojure.string/split % #",")
(clojure.string/split string #"\n")))
(map #(str->int (second %))
(slurp filename))
(defn str->int [str] (Integer. str))
(def vamp-keys [:name :glitter-index])
(def conversions {:name identity :glitter-index str->int})
(defn convert [vamp-key value] ((get conversions vamp-key) value))
(defn mapify
"Convert a seq of vecs into a seq of maps, & convert num-strings to numbers:
([\"Edward Cullen\" \"10\"] ...) to ({:name \"Eward Cullen\" :glitter-index 10} ...)"
[rows]
(map (fn [unmapped-row]
(reduce (fn [row-map [vamp-key value]]
(assoc row-map vamp-key (convert vamp-key value)))
{}
(map vector vamp-keys unmapped-row)))
rows))
(mapify (parse suspects))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; GOAL
;; CONVERT THIS:
; "Edward Cullen,10\nBella Swan,0\nCharlie Swan,0\nJacob Black,3\nCarlisle Cullen,6\n\n"
;
; INTO THIS (via parse):
;(["Edward Cullen" "10"]
; ["Bella Swan" "0"]
; ["Charlie Swan" "0"]
; ["Jacob Black" "3"]
; ["Carlisle Cullen" "6"])
;
;; AND THEN INTO THIS (via mapify):
;({:name "Edward Cullen", :glitter-index 10}
; {:name "Bella Swan", :glitter-index 0}
; {:name "Charlie Swan", :glitter-index 0}
; {:name "Jacob Black", :glitter-index 3}
; {:name "Carlisle Cullen", :glitter-index 6})
;; NB vecs -> maps & string-values -> number-values
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Re: mapify
; This: (map vector vamp-keys ["Edward Cullen" "10"])
; evaluates to this: ([:name "Edward Cullen"] [:glitter-index "10"])
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; QUESTION: WHAT are the ARGS for these PARAMETERS:
; [row-map [vamp-key value]]?
;(reduce (fn [row-map [vamp-key value]]
; (assoc row-map vamp-key (convert vamp-key value)))
; {}
; ([:name "Edward Cullen"] [:glitter-index "10"]))
@johnmi A little experimentation with reduce
on a different function may be helpful to understand.
user=> (defn print-args-then-conj [x y]
(println "x=" x "y=" y)
(conj x y))
#'user/print-args-then-conj
user=> (reduce print-args-then-conj [] [5 7 11 13])
x= [] y= 5
x= [5] y= 7
x= [5 7] y= 11
x= [5 7 11] y= 13
[5 7 11 13]
Also the doc string for reduce
, which you can see via (doc reduce)
at a REPL prompt, may be useful?
Thank you @andy.fingerhut. I just discovered that there is a channel for #bravendtrue and will move my question and your answer over to it. And will close the question for this channel.
No problem. Your question is definitely relevant for the #beginners channel, too
I just dont want abuse slackers with duplicate postings. Altho beginners probably gets more traffic. thanks again.