Hi everyone I was reading about final in a Java book and how java.lang.String is a final class so it can't be extended and the book was explaining about how it would be dangerous and chaotic to have alternative implementations of String be accepted polymorphically by methods but Clojure's polymorphism allows you to extend even final classes, if so then wouldn't that be dangerous also or is there something I'm not understanding that makes this OK to do?
@flyingpython In Java, polymorphism is intrinsically tied to inheritance. In Clojure, that is not the case.
Clojure's polymorphism is, essentially, a la carte. Protocols allow you to associate type-based dispatch with additional functionality.
Would it be fair to say that Clojure's protocols would allow you to create dangerous and chaotic protocol implementations, if you wished, perhaps in a similar way that the Java book claims that extending java.lang.String might be? At least, it doesn't seem like Clojure somehow prevent that from happening.
I agree that some kinds of danger and chaos are avoided by not having implementation inheritance -- just not all of them. There are so many kinds of danger and chaos, after all 🙂
One person's chaos is another person's ordered functionality... 🙂
For example, in next.jdbc
, it has the concepts of "sourceable" -- something you can make a datasource from -- and "connectable" -- something you can make a connection from. That allows you to treat a number of things in a consistent, polymorphic, manner and work in a natural way with things that perhaps weren't designed with the affordances you need.
This is why you should only extend protocols you own or types you own. But, sure, you can write dangerous, chaotic code with Clojure (just like any language, even Java, despite final
🙂 )
Ah OK thanks for the explanation guys, so I guess it is mostly avoided by convention of not doing unwise things, it seems super cool that you can do that in Clojure though 🙂
Thanks for the explanations, yes the book I am working through on Clojure said working with databases is a common use case for Clojure's polymorphism
And it's probably worth noting that next.jdbc
extends Sourcable
to String
so that you can polymorphically call get-datasource
on a JDBC URL as a string, just like you can call it on an associative data structure.
Wow that's super cool!
I know I ask this yesterday but the solution then do not seem to solve it
clj::ground_up.chapter5=> (ns ground-up.chapter5)
nil
clj::ground-up.chapter5=>
; Syntax error compiling at (chapter5.clj:38:1).
; Unable to resolve symbol: defn in this context
code :
(defn palindrome?
"Checks if a word is a palingdrome"
[word]
(= (seq word) (reverse word)))
In a cider repl, how do I print a “complex” map in a def-friendly way? I would like to be able to cut & paste from repl into a def in testing code, but I run into issues like lists being (1 2 3) in the output instead of ’(1 2 3) or (list 1 2 3), for example.
Do I have to do prn and use reader?
Every now and then I just quote such "lists" manually.
If this is for debugging/inspection you can use cider inspector or debugger and press d
when you're focused on the right object - it will prompt you for a var name.
(walk/postwalk (fn [x] (if (and (seq? x) (not (vector? x)))
`(~'list ~@x)
x))
{:a (range 3)
:b {:c (range 3)}
:d (map inc (range 3))
:e [(map inc (range 3))]})
bit hacky but can work for yayou'll need to tweak the predicate a bit i'm sure but seems promising
Hm, thanks 🙂
@jumar, I’ve been playing around in the repl to build a test, and wanted to transfer an expected result to a test case.
(def foo (quote ,,,,))?
Can someone explain this :
(defn palindrome?
"Checks if a word is a palingdrome"
[word]
(= (seq word) (reverse word)))
(defn countPalingdromes
"count the number of palingdromes between 0 and 9999"
[]
(->> (range 0 9999) (filter palindrome?) (count)))
error message :
; Execution error (IllegalArgumentException) at ground-up.chapter5/palindrome? (form-init12029216532296771069.clj:41).
; Don't know how to create ISeq from: java.lang.Long
palindrome expects a sequence and it's being given a number. try:
(->> (range 0 9999) (map str) (filter palindrome?) (count))
thanks
still a lot to learn
Anyone know how to request with content-type image/png in reitit? I need to create upload image API. Multipart also won't works, i keep getting ClassNotFoundException javax.servlet.http.HttpServletRequest
how do I make it work that the message is printed
(def logging-enabled :true)
(defmacro log [message]
(if (= logging-enabled :true)
'(prn message)
nil))
(macroexpand `(log :hi))
To define macros, you need to understand the difference between • quote (’ apostrophe) • syntax-quote (` back-tick) • unquote (~ tilde) The syntax quote needs to be used, when you need to create an expression using a variable’s value, not the variable itself, done by unquoting the variable. In your example you need to syntax quote the (prn …) and unquote message. Also, you need to quote nil, since that is a return expression.
right now I see (prn message)
as output
before I forget this is the challenge I try to solve:
; Write a macro log which uses a var, logging-enabled, to determine whether or
; not to print an expression to the console at compile time. If logging-enabled
; is false, (log :hi) should macroexpand to nil. If logging-enabled is true,
; (log :hi) should macroexpand to (prn :hi) .
not funny
if I restart vs code I see this as soon as I do crtl - enter
Syntax error compiling at (chapter5.clj:62:1).
; Unable to resolve symbol: defmacro in this context
even if I do (ns ground_up.chapter5)
wierd, if i do crtl-enter
first on a defn
and then on the defmacro
it works, If I do tit direct on a defmacro
I see the above error
Hello Clojurians, I am trying to build subsequences from an original seq according to specific criteria (4Clojure p53, https://www.4clojure.com/problem/53#prob-title). I am trying to implement it via a recursive function, any suggestions for a higher level approach? Thanks in advance.
@mzuppichin a code walk through of how I put together first a very low abstraction loop recur and then used partition for a higher level of abstraction https://github.com/practicalli/four-clojure/blob/master/src/four_clojure/053_longest_increasing_sub_seq.clj
There is also a video of this walk through here https://www.youtube.com/watch?v=pyIbP4BOGpQ&list=PLpr9V-R8ZxiDjyU7cQYWOEFBDR1t7t0wv&index=36
@jr0cket Thanks sincerely, I have tons of material to study now!
Thanks for the quick and exhaustive response!
If you can find any other solutions, do let me know 🙂
any expert who can give feedback on my code : https://github.com/RoelofWobben/Learning_in_public/blob/main/ground_up/src/ground_up/chapter5.clj
The namespace in the file should use a dash instead of an underscore
(ns ground-up.chapter5
(:import [java.time LocalTime]))
However, the file name should remain as an underscore, as the Java virtual machine that this Clojure code runs on does not support dashes in file names. I appreciate this is awkward at first.I might model the schedule as a sequence of activity name with time entries
chancing the name into (ns- ground-up.chapter5)
does not solve the problem
I still get this error message :
; Unable to resolve symbol: defmacro in this context
I am unaware of the problem, I havent looked into the history. However the ns definition I suggest is the preferred syntax.
@henryw374 how do you mean that ?
oke, if I do crtl + enter on the new name it works
I am unclear why macros are used. They are a small part of writing clojure applications and require more of a learning curve if you are just beginning. Not something I can help with, sorry.
NP. it seems your suggestion worked on chancing the name
(def my-schedule
[{:activity "brush teeth" :time "7"}
{:activity "gel hair" :time "7.15"}])
for example. then you can have the same fn work on different schedules. and you can validate them to see if they make any sense
There is also the #code-reviews channel that may elicit more feedback 🙂
Do any of you know if the spit function reads entire file content when using the append true parameter?
Thanks, I ask there
@henryw374 I think that I understood what you mean but I also think that is more then I can chew now. Writing clojure now for 3 - 4 days
Confusing this :
user=> (def x (future (prn "hi") (+ 1 2)))
"hi"
#'user/x
user=> (deref x)
3
why does hi printed direct and the adding later
why not both later ?
is there a function build-in which reverses the args of a binary function. i.e. which maps f
to (fn [a b] (f b a))
?
of course I can write this but it is one of those functions like comp
which is useful when doing functional manipulation
I need this most often when using condp
to reverse the args of the predicate
I need to find the most frequent element of a sequence, and how many times it occurs. The way I'm doing it seems awkward.
(defn most-frequent [items]
(reduce (fn [[td c] [td' c']]
(if (< c' c)
[td c]
[td' c']))
[:empty-set 0]
(frequencies items)))
So (most-frequent '(a b a b c a b a b a a a d))
returns [a 7]
(->> (frequencies '(a b a b c a b a b a a a d))
(sort-by val >)
(first))
?(->> (frequencies [1 2 3 1 3]) (sort-by val >))
([1 2] [3 2] [2 1])
ok, sorting a map using sort-by val
is something i wouldn't have guessed. The code is concise, but I don't really need to sort, I just need to find the maximum element
do you need the key or the val?
or both?
perhaps something like max-key would be cleverer?
once I have the key, I can get the value, right?
if you just want the value
(apply max (vals (frequencies '(a b a b c a b a b a a a d))))
https://clojuredocs.org/clojure.core/max-key#example-5490032de4b09260f767ca79
oh nice! I wasn't aware of max-key 🙂
the doc for max-key suggests this recipe:
; find the key that has the highest value in a map
user=> (key (apply max-key val {:a 3 :b 7 :c 9}))
:c
so perhaps something like the following will give me the pair
(apply max-key val {:a 3 :b 7 :c 9})
max-key
is basically what my call to reduce
is doing, more or less.
yeah, seems like it.
cool. I'm glad I asked. thanks for the leads.
when using something like max, one must consider the cases of empty input.
When I first checked out the frequencies
source, I learned like 3 new things at once. And the function is only a couple of lines long
for example my function dies when given an empty list.
It’s very motivating to read the clojure.core
sources for these utility functions.
(some->> (frequencies [])
seq
(apply max-key val))
Some threader can help...
I think the documentation for condp
is wrong. can someone help me read it and figure out if I'm confused. The documentation says that the expression (pred test-expr expr)
is evaluated repeatedly, however it appears to me that expr
is only evaluated once, into a tmp-var and the expression that is evaluated repeatedly is (pred-test-expr tmp-var)
This is of course the desired behavior, but not the documented behavior.
I think that's what that doc is trying to convey
I agree that that is what's intended, and it is what the user would assume from NOT reading the doc. But when I read it carefully, I had to perform an experiment to verify.
if you're using a side effecting expr where you would see a different result between those two interpretations, then I would suggest maybe that's a bad idea
I'm writing a macro which expands to several invocations of condp
. I needed to know whether my macro needs to capture the value of the expression in a let
or whether condp
already does that for me.
as to whether it is a good idea to have side effects in the given expression, I understand your concern. But if I'm writing a macro where the user passes the expression to me, I don't have the privilege of requiring that there be no side effects.
sure you do - just say that's not allowed in the docs :)
Well I prefer that if the user gives me an expression with side effects, then those side effects are only effectuated a maximum of once. That is much friendlier for debugging.
And is in fact what condp
does, despite a biblical fundamentalist reading of the holy documentation text 🙂 grins
With Calva you should always start with loading the file. Otherwise, things are in flux.
Hello all, I'm trying to create a CSV using (https://clojure.github.io/data.csv/) , however I don't want to write to disk and would like the output to be a byte array. Because I'm unfamiliar with writer, I'm not sure how to do this.
(with-open [writer (io/writer file-path)]
(clojure.data.csv/write-csv data file-path))
How can I change this to return a byte array and not write to disk? Thanks
Here is an example of the macro, https://gitlab.lrde.epita.fr/jnewton/clojure-rte/-/blob/master/doc/genus.md#typecase if you're interested
I am working on rewrite-cljc docs and want to check my terminology usage. When I first came to Clojure I really had no concept “form” or “sexpr”. Maybe I still need help. Can these terms be used interchangeably? Is the difference https://clojure.org/guides/learn/syntax#_structure_vs_semantics?
(let [bytes (java.io.ByteArrayOutputStream.)]
(with-open [writer (io/writer bytes)]
(csv/write-csv writer [["a" "b" "c"] [1 2 3] [4 5 6]]))
(str bytes))
I know that a string in quotes is an expression, but I'm not sure whether a non-parenthesized piece of text is a form????
strings and numbers and symbols are s-expressions.
are they forms?
Thanks. I changed the last part and got what I needed.
(defn data->byte-array [data]
(let [bytes (java.io.ByteArrayOutputStream.)]
(with-open [writer (io/writer data)]
(csv/write-csv writer data))
(.toByteArray bytes)))
(data->byte-array data) ;; [34, 91, 34, 34, 48 ...]
(type (data->byte-array data)) ;; [B
Thanks again!Confusing this :
user=> (def x (future (prn "hi") (+ 1 2)))
"hi"
#'user/x
user=> (deref x)
3
why does hi printed direct and the adding later
why not both later ?future runs the expression in a different thread
concurrent to the main repl thread
(although they both share the same stdout which can be confusing)
from (doc future)
> Takes a body of expressions and yields a future object that will
> invoke the body in another thread, and will cache the result and
> return it on all subsequent calls to deref/@.
so "hi" is being printed in thread 2, then the deref returns the result of the expression and prints it in the main thread
s-expression is either an atom (including strings and symbols) or an expression (x y …)
where x and y are s-expressions
so literals like [1 2 3]
or {:x 1}
(vectors and maps) are not s-expressions.
s-expression is a subset of form in clojure terminology imho
oke, so printed cannot be deferred. If I would do there another calculation then both were deffered ?
it sounds like you are expecting the behavior of delay
a delayed expression is only run once you deref or force the delay (and happens on the same thread)
I expect nothing but try to understand what happens. It thought both are deffered but I see the output of `(prn "hi") direct and I try to understand why that one is direct executed and the calculation is deffered
there is no real ordering of output from another thread (the future) and the output from the repl process (prompting you for input)
they both just print whenever they want, they are independent threads
so basically it is a race condition, how the output of the repl is interleaved with the output of the future
future
will evaluate everything in its body as soon as possible, in a separate thread, subject to operating system, thread scheduling, etc. constraints.
so "hi" may print out first, or after #'user/x, or after you deref
^^ future is not about future evaluation, it's about getting the result in the future
evaluation is immediate and concurrent
interesting
Clojure Applied has a great chapter on all this btw, also the author is quite strong and handsome
@roelof perhaps one source of your confusion is that some output in the repl is the implicit print of values as you ask for them to be calcuated, and other output is arbitrary printing behavior?
oke, so using a future
is not a good thing because you never know when the result is returned. And there im confused
the result is returned when you ask for it
any random prints are done as they are executed
this is why I was pointing out the distinction between things implicitly printed (because your REPL form returned them), and things explicitly printed (because you wrote code that prints)
the result of an expression, and output printed by an expression are not the same thing
> oke, so using a future is not a good thing
a future
is a thing that could be exactly what you need or very inappropriate. Can you explain what you want to accomplish and the advice can be more tailored to that?
oke, lets say we have this : (def x (future (* 3 4 ) (+ 1 2)))
I see a message #'ground-up.chapter5/x
which is the 3
but where is the outcome of ( *3 4)
?
(do (+ 1 2) (+ 10 20))
will return 30
. the (+ 1 2)
is computed and ignored as its unused anywhere and not returned
oke
this isn't just a property of future (which contains an implicit do), it also applies to other places that contain a do block, like let, fn, defmacro, doseq, loop...
all forms in the do block but the one you return are only useful as side effects
oke, I think I understand it but still I think a wierd example in the book to explain futures
it's showing that the execution happens immediately (via the print side effect), and you can get the value whenever you are ready for it
thanks
it seems like it really demonstrated what's going on. the println happened immediately and the value comes when derefed. Pretty good probing of how future runs immediately and caches its value for dereferencing
anyone more who want ot give feedback on my code.See question on the code-review chapter
Hi, I have this deps.edn
{:paths ["src" "resources"]
:deps {org.clojure/clojure {:mvn/version "1.10.1"}
aysylu/loom {:mvn/version "1.0.2"}
org.clojure/math.combinatorics {:mvn/version "0.1.6"}}
:aliases
{:remote-repl {:extra-deps {vlaaad/remote-repl {:mvn/version "1.1"}}}
:reveal {:extra-deps {vlaaad/reveal {:mvn/version "1.0.130"}}}
:test {:extra-paths ["test"]
:extra-deps {org.clojure/test.check {:mvn/version "1.0.0"}}}
:runner
{:extra-deps {com.cognitect/test-runner
{:git/url "<https://github.com/cognitect-labs/test-runner>"
:sha "b6b3193fcc42659d7e46ecd1884a228993441182"}}
:main-opts ["-m" "cognitect.test-runner"
"-d" "test"]}
:uberjar {:extra-deps {seancorfield/depstar {:mvn/version "1.1.128"}}
:main-opts ["-m" "hf.depstar.uberjar" "aoc.jar"
"-C" "-m" "stuartstein777.aoc"]}}}
And this .clj file:
(ns stuartstein777.2020.day10
(:require [clojure.string :as str]
[clojure.math.combinatorics :as combo]))
WHen I try to run anything in the repl in this namespace I just get the error:
Execution error (FileNotFoundException) at stuartstein777.2020.day10/eval1477$loading (day10.clj:1).
Could not locate clojure/math/combinatorics__init.class, clojure/math/combinatorics.clj or clojure/math/combinatorics.cljc on classpath.
I'm using INtelliJ, after recent update I get warnings about old project types and it asks to convert them. Now stuff that worked pre-update is broken.
Any ideas?Cant run REVL either, and this also worked until yesterday. Now it says cant run REVL, no project file found.
Maybe I just need to recreate the project from scratch with clj-new ?
it sounds like something in IntelliJ that needs fixing, not clj
yeah, i just tried another project that 100% worked, and woudl run REVL too. Now it doesn't work either.
Man, I have no other editor setup to do clojure
Guess I can use my other machine that doesn't have latest IntelliJ
running clj in a terminal, then using require
to load your namespace should still work (or at least get further than not seeing a dep that's in your config)
Thanks @jimka.issy and @delaguardo, I guess I’ve tested the waters for strong opinions on this. I think I’ll just go ahead and describe the terms rewrite-clj already uses with the caveat they might not be absolutely technically correct.
You might want to post something in the #cursive channel
I just posted this solution with max-key a few days ago on Twitter https://twitter.com/PrestanceDesign/status/1336726602777038849
max-key
is great!
Found this definition which seems to match rewrite-clj usage: https://www.braveclojure.com/do-things/#Forms
Hi Everyone, I am a Javascript developer, I recently gotten introduced to Clojure world by a React ClojureScript application. Are there any good resources you would recommend that would will help me with this transition?
@singhamritpal49 If you're using Reagent, this might be a nice one: https://www.learnreagent.com/
@singhamritpal49 There's also lots of resources listed here: https://gist.github.com/yogthos/be323be0361c589570a6da4ccc85f58f
Hmm.. the free version of that course never loads for me.. I just get loads of errors in the js console
In chromium it works fine, the errors were just for firefox
Maybe pass that as feedback to the author. It's kind of ironic that a webdev course doesn't work in all browsers.
yes, that's the same thing I thought 😂 I already wrote about this problem in the chat that popped up
Hi! This is a good challenge for Clojure: https://twitter.com/wesbos/status/1337453660482187268 I'm sure there are a clean and simple way to solved this. What functions do you think are appropriate in order to achieve the results?
A library was used, but I like the R version 👍 https://twitter.com/matthewpaulking/status/1337461670243799040
I have looked into the question and I am thinking of using merge-with, reduce, etc.
(let [col [["name" "id" "height"] ["Bob" "2" "50"] ["John" "1" "45"]]]
(map #(zipmap (map keyword (first col)) %) (rest col)))
({:name "Bob", :id "2", :height "50"}
{:name "John", :id "1", :height "45"})
@admin055 Shouldn’t it be group-by :id
instead of group-by :name
?
I suggest to avoid the shortcut for the anonymous function, so that you can name the entry param. It helps the code staying readable.
Another suggestion is to use ->>
, it helps reading the transformations as they occur chronologically.
parse-array
is fine
If you use my extended version of group-by
, you can have something even shorter and easier to read:
(def result
(->> [arr1 arr2 arr3]
(map parse-array)
(apply concat)
(group-by :id identity merge)
vals))
The source code of my group-by
is:
(defn group-by
"Same as clojure.core/group-by, but with some handy new arities which apply
custom map & reduce operations to the elements grouped together under the same key."
([kf coll]
;(group-by kf identity conj [] coll)
(cc/group-by kf coll))
([kf vf coll]
(group-by kf vf conj [] coll))
([kf vf rf coll]
(group-by kf vf rf (rf) coll))
([kf vf rf init coll]
(->> coll
(reduce (fn [ret x]
(let [k (kf x)
v (vf x)]
(assoc! ret k (rf (get ret k init) v))))
(transient {}))
persistent!)))
For more info on this group-by: https://twitter.com/VincentCantin/status/1337815470469042176
Thx a lot @vincent.cantin!
I’m doing well with “simple” recursion, like with loop/recur or without. But what I am struggling with is the case when I have to recur into a list of things … like when generating a tree or explore multiple paths
I have gotten into the habit of starting with something like an secd or cek machine whenever I need to process a tree, because those are abstract machines for evaluating programs, and programs are trees
the idea of storing continuations in a stack, processing a list of results and then doing something in the middle of a tree, etc are common features of tree processing and program evaluation
I can't claim it is good, I don't think the programs that come out of it are particularly readable
interesting i should look into that ..
but it seems to be a universal technique
the last thing I did that with is a pretty printer for graphql schemas and it is very ugly
i need to read about some basic algorithms about path exploring i think
another thing you might look at is zippers
advent of code related 🙂
clojure ships with clojure.zip, which doesn't get a lot of love
there is also clojure.walk
oh zipper may actually be what i want
related to zippers are lenses, which there are a few clojure libraries for, or something like spectre
i think i basically need something higher level that allows me to give it a function to answer ‘what are the children for this node’ repeatedly until i have no more data for that branch
looks like a zipper may be able to do this
if you need to edit nodes in a nested immutable data structure, zippers are awesome. for simply walking a nested data structure, tree-seq
can be an easier alternative
i need to generate it first 🙂
and then count stuff in it