This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2019-08-24
Channels
- # announcements (1)
- # beginners (113)
- # calva (16)
- # cider (6)
- # cljsrn (1)
- # clojure (104)
- # clojure-argentina (2)
- # clojure-dev (3)
- # clojure-italy (1)
- # clojure-nl (10)
- # clojure-spec (6)
- # clojure-uk (4)
- # clojuredesign-podcast (44)
- # clojurescript (25)
- # core-async (2)
- # datomic (21)
- # emacs (14)
- # events (1)
- # figwheel-main (12)
- # fulcro (7)
- # joker (2)
- # leiningen (1)
- # mount (7)
- # music (1)
- # off-topic (16)
- # pedestal (3)
- # re-frame (8)
- # reagent (8)
- # reitit (11)
- # shadow-cljs (4)
- # spacemacs (16)
- # sql (1)
- # tools-deps (14)
- # vim (1)
I'm not sure if this is the appropriate place for this discussion, but I've been meaning to field test my understanding of some of Rich's justifications of clojure/spec
.
I'm rolling around the idea in my head that types and specifically the way we use them can essentially be broken down into far more basic ideas. We use type systems in languages such as Scala and so on to represent both the domain of our world with a common language and the data that exists in conjunction with that domain. Following this, we attach these representations of what are essentially just data shapes to functions all across an application attempting to document and describe what's going where, what's needed where, and how we use and transform from one shape to the next. That's a lot of fluff to say that we are simply using types as convenience in either A. holding the "grand-shape" of data in our heads and B. making assertions on the code that prevent simple type mistakes such as passing an int instead of a list of ints or failing to return the appropriate data shape from a particular function. That sounds awful like "documentation" and "tests". So, why not just write the tests or, rather, specifications about things flowing through functions. We can express even more this way. And, while we lose out on the benefit of being required to provide types (if they're inferred it's still good to place them), we gain the benefit of no longer needing to represent overly complex types that start to miss the point of typing in the first place (see Rich's Transducers talk). Of course, this assumes that while we work, we studiously are weaving this into our natural flow of development and have the tooling to support a sufficiently fast feedback loop to approach the benefits of compile-time "assertions". But, once we do, we can really get at the problems that types have been trying to solve while getting rid of the natural bulk and overhead of them. So, tldr (and suuuuper simplified); types are just DSL's for writing tests that run at compile-time, what's the harm in moving them provided modern tooling and development/build flows?
What's missing in this argument.
@dfehrenbach04 This might be better suited for Clojureverse or AskClojure
Yeah, one of those two venues would provide a longer history to others of viewing the answers. The short answer I keep from some of his talks is that every technique we use has benefits/advantages and costs/disadvantages (or if they have no benefits/advantages, we should not be considering them). Type systems have disadvantages that Rich finds to be a source of accidental complexity in his work, that he would prefer to avoid. spec plus generative/property-based testing are a way at getting at more of the properties of your code than today's type systems can specify (not guaranteed, but with high enough probability).
Or another variation on that, type errors in Clojure code tend to be fairly "shallow bugs", versus the deeper functional bugs that today's type systems often cannot help prevent.
Note that these are my takes on his arguments -- not his arguments verbatim, so please do not represent what I say as his views.
More in his talk on Spec here: https://github.com/matthiasn/talk-transcripts/blob/master/Hickey_Rich/ClojureSpec.md
@dfehrenbach04 IMO, the whole topic is largely a matter of composition, abstraction and communication. At the highest level of abstraction we can consider some things true by definition (Category Theory, math). As we move towards solving a specific problem we quickly have to pick more and more detail (physics, computer hardware, etc..). As we focus in on our problem domain we can choose to pick up "domain" ideas (students, teachers, classrooms etc...). Type's should be a way of communicating relationships between idea's at these various levels. That communication is often useful at development time (where the compiler functions and where static types operate). But it's also useful for creating the application itself (e.g a spec error can easily become a user error, api return message, etc...). That is, that information is often useful at runtime. Spec lets choose when compile vs runtime and it also lets you choose how much you want to use it. I predict in 30 years (assuming we all make it that long) The norm will be languages that let you operate with more flexibility (gradual typing, compile vs run time, relaxed constraints at certain points, etc...)
what do you mean by "moving them"? @dfehrenbach04
Where I run into issues with types is higher order functions. I'm sure the folks who are super into Haskell have a good answer for this, but I have no idea how my favorite functions, map
, reduce
, and filter
work in typed languages, especially without being extensible. The same goes for functional polymorphism. It also seems to defeat the whole point of "coding to an abstraction".
At the very least I think it works kind of like... "upside down abstractions"
"Moving them" as in moving when you see the error message from compile time to run time (when your tests "go")
ah, I see
well I get the need for it, as in... there is a certain class of errors that can be prevented by using types. i.e. I've worked in large Python code bases where making changes is very scary because you have no idea what's going to break
So you make a change, test as much as you can, and push to production ... only to find out two weeks later some page is down
And sure, you can argue that "you should have tested better"
So, yeah, if you're just running a script then compile-time or runtime-errors don't really make a difference, but if you're talking about systems with multiple entry points like a web application, the story is a little different, especially if you're iterating rapidly
Where I really get hung up is reduce
.
how on earth are you supposed to say what the input types and output types of reduce
are?
same goes with transducers, it seems effectively impossible to type those, or at least it requires some level of string theory and tesseract geometry which is beyond me π¬
But I see the arguments for types. Rust makes a super convincing argument for types. Otherwise it's just too much a mental impedance for me π
You might be right. I've been thinking about it in terms of Rust which (I think?) has a more concrete type system.
Hello #beginners! I'm new to Clojure and trying to learn by following this post to create a blog: https://cjohansen.no/building-static-sites-in-clojure-with-stasis/. I'm currently running into this error when I start the server: Caused by: java.lang.RuntimeException: No such namespace: str
. Any idea how do I use the str
namespace?
Thanks @dpsutton ! I need to read about how namespaces work π
Right now I just edit files in Emacs (Prelude) and when I save the whole thing reloads. Good stuff, but I want to move to REPL based development, so that I can more easily change things.
Can anyone give me a hint how I move from lein ring server-headless
to running my server in the REPL?
Usually, I run lein ring and lein repl and connect to lein repl
I then connect cider to lein repl (with cider-connect-clj)
You can then use you repl to develop your functionality and normally lein ring can auto update
so you donβt start your app inside the repl, you just run lein ring server
in a separate window/session next to it
If someone knows about clojurescript and reagent, please check the #clojurescript channel because I'm having a #beginners problem and wasn't sure wether to ask there or here π
@st3fan yes that is about it.
Obviously, there are some drawbacks, but, it forces me to write functions I can test in the repl, and I test ring by sending request inside my repl xD
Not sure if it this is the best, but I have a good workflow with that.
In ClojureScript, how do you use react component that rely heavily on mutability? I have a library (react-chart-editor) that I would like to use, but the components never rerenders whenever the state change. I use reagent
. I tried to bypass CLJS completely as well, using react-dom, but I did not get a better solution.
Getting pretty excited about Clojure again but there are many things i donβt really get yet
Is https://github.com/dakrone/clj-http a good HTTP client to chat with REST APIs?
@st3fan this is the one I use for testing my ring server
This may be the wrong place to ask this question. I'm interested in giving clojureScript a try. I've liked a lot of what I've seen and read about it. Is there currently a way to get up and running with clojureScript without installing java? What is the current best option for this?
@adam.the.sherwood ClojureScript's compiler requires the JVM (so, no, you need "Java" installed -- at least a JRE or JDK).
There is some experimental support on Lumo. I'm no expert on cljs, but it seems to work: https://github.com/anmonteiro/lumo#compile-clojurescript
Yeah, I was about to add the caveats of lumo/plank/etc...
Ahh. Okay. Thank you both. Is Lumo reliable as far as you are aware?
Its quite stable/mature as a Node.js platform as far as i know. has frameworks like https://macchiato-framework.github.io/
but the obvious issue one might have when using this as the sole cljs platform is the lack of tooling like leiningen/boot/tools.deps. specially when building frontend apps. they all need the JVM and pretty much make the cljs frontend dev experience what it is π
Why would you avoid Java?
Good to know
I use shadow-cljs, and I donβt see any difference.
I'm just wanting to avoid complexity. I'm comfortable around javascript, but don't feel like grappling with java in addition to learning cljs
I would say knowing npm and the JS Ecosystem would provide a much bigger advantage
great! I'll have to do some research!
npm install -g shadow-cljs
Helps for starting with the config file
That's great help. I'll have to give it a try!
Good luck and welcome in the community :)
Thank you all very much! Very helpful
I'm learning how to parse XML. I want to emit a clojure datastructure
some of the XML properties are multiples, is it alright to just cram them all into a sequence [to ge ther]
?
as in, you are writing your own XML parser in Clojure?
Umm yes!
I am. I want to read a big XML file and create a clojure datastructure from it.
No problem if that is what you want to do. There are multiple XML parsers written in Clojure and Java, if you want to use those instead.
oo that's even better
i like the way you think. find an open source bicycle instead of building my own.
They all produce their own data structures as a result, and not all of them will produce the same things.
As I said, it is certainly fine if your goal is to learn more about Clojure and/or XML by writing your own.
hmm well it's a huge file you see, it's 50 Megabytes, it's a Japanese Dictionary, and I have concluded that each entry can simply be a {:map "withKeyValPairs"}
thanks i'll take a look at some and see what makes sense
Any recommendations?
Zippers look tremendously useful
I'm trying to create a li
element using the javascript interop, been following this: https://www.spacjer.com/blog/2014/09/12/clojurescript-javascript-interop/ but it talks about JS objects and I'm not quite sure about the difference between those and DOM elements?
I'm working with TaggleJS
https://sean.is/poppin/tags and I'm trying to format the outputted tags.
:tagFormatter (fn [li]
(let [children (.-children li)]
(.log js/console children)))
I need to pass a function which takes the li
, manipulates it and it's children, and returns a new li
for taggle to use.
HTMLCollection { 0: span.taggle_text, 1: button.close, 2: input, length: 3, β¦ }
forms.cljs:121:30
I've tried accessing these children with (:0 children)
and (get children 0)
, but using .log js/console
isn't giving me anything but null. Any ideas? My end goal is to simply manipulate the classes of the text and the close button, as well as adding another span
in the middle. Sound doable?Update: Realised that I needed to use JS functions to work with JS stuff, so here's the current function. I'll neaten it up as I learn more.
:tagFormatter (fn [li]
(let [children (.-children li)]
(.add (.-classList (.item children 0)) "tag")
(.add (.-classList (.item children 0)) "is-dark")
(.add (.-classList (.item children 1)) "tag")
(.add (.-classList (.item children 1)) "is-delete")
))
Looking good now! Just got to use CSS to style the rest. I got it π
when you find yourself doing a lot of java/js interop, ..
and doto
are some handy macros
I'll look them up, thank you!!
I apologise for the horrible formatting of my paste π
warning: didn't check or run this so could contain errors but those two applied to your case:
(doto (.. li -children (item 0) -classList)
(.add "tag")
(.add "is-dark"))
(doto (.. li -children (item 1) -classList)
(.add "tag")
(.add "is-delete"))
I'm actually just going to make it myself in clojure and maybe even release it publicly if its clean
as TaggleJS is not very nice
too much has been done for you, not very customiseable
Probably just a side-effect of not being made in/of LISP. Although Javascript gets pretty damn close with callbacks ... at some point the rigidity of expression causes kinks in the chain
I really hated TaggleJS so I rolled my own thing. Here's what I came up with! There's no autocomplete yet, but there's some easy room for expansion now that I did it my own way π
hello, could anybody give me some hints on how to write tests loop/recur functions?
what do you mean @andrea.imparato
yeah could be because I'm trying to test a function that I wrote for a tic tac toe game
let me paste the function
(defn -main [& args]
{:pre [(or (spec/valid? ::args args)
(spec/explain ::args args))]}
(loop [game-state (-> (config/read-config-file (first args))
(game/initialize))]
(grid/print-grid game-state)
(when (nil? (:metro.game/winner game-state))
(recur (game/play game-state)))))
how would you test this function?
and there's really not much to test here. the logic allows for no hidden things. what you really want to test is (game/play game-state)
but really there's some function (move game-state player-input)
somewhere in your code that you want to test. the rest is printing and just a loop
so you think testing the loop itself doesn't make really sense?
since there's really not much logic there
its print, if winner stop, else play. there's simplicity in it and no edge cases. not sure what a test would give you
and all it would test would really be that (game/play game-state)
correctly sets a winner if indeed there is a winner
yeah I actually think the same, I just wanted to find some confirmation π
thx for the help @dpsutton π
Is this an ok guide to enter the REST world in clojure? https://medium.com/swlh/building-a-rest-api-in-clojure-3a1e1ae096e
let us both follow it and let the world know
I think it is not quite right to call this a REST tutorial, because all request are mapped to a single HTTP verb ( GET )
yes, I noticed that too. I was wondering if the libraries they use there are the 'mainstream libraries' for this kind of project
I really hated TaggleJS so I rolled my own thing. Here's what I came up with! There's no autocomplete yet, but there's some easy room for expansion now that I did it my own way π