I'm almost 99% sure both jobs were places that bought into some dynamic developer who promised unicorns and rainbows and then left them with a huge clojure project have their eyes bleed to. No thanks.
It takes more than just a language to create a productive development environment in 2020, especially one which is so flawed by designed to the point of not even being statically typed.
Interesting point. Sadly, it seems engineers at Apple, Cisco, Walmart, NASA, CircleCI, Pandora, Grammarly, Funding Circle, Nubank and hundreds of other companies are amateurs who don't know jack-shit about challenges in the industry and keep building their sand-castles using their incredibly flawed tools. I'm sure, these losers would soon vanish from the radar and we would never hear about them. Just give it a few years.
I was more trying to show that the API could be better and hoping this would put pressure on core devs to do it properly.
Keywords don’t form a DSL in Specter, they just do keyword navigation into maps, the same way ‘0’ navigates into the first element of a list.
This touches upon a really nice element of Specter, which is its pattern for reuse. Here’s a very real but deliberately simple example of using it:
(def chat-threads
{[“sova” “tekacs”]
[{:text [“hey” “you there?”]}
{:text [“line 1” “line 2”]}]})
(def ALL-TEXT
[sr/ALL :text sr/ALL])
(defn text-for [chat]
(sr/select [chat ALL-TEXT]))
(def ALL-CHAT-TEXT
[sr/MAP-VALS ALL-TEXT])
(text-for [“sova” “tekacs”]) ;=> [...]
Here the navigator into a list, then the :text field and then the list is bottled simply by putting several navigators in a vector.Then, it can be used alongside other navigators in a first class fashion — [chat ALL-TEXT] is just a nested vector. :)
{:all {:a 2} :foo {:a 4}}
Maybe namespaced keys would fit that usecase This is the TXR Lisp interactive listener of TXR 243.
Quit with :quit or Ctrl-D on an empty line. Ctrl-X ? for cheatsheet.
Give me all the .c files: 1> (glob "*.c")
("abcd.c" "args.c" "arith.c" "buf.c" "cadr.c" "chksum.c" "combi.c"
"crazyffi.c" "debug.c" "dict.c" "eval.c" "ffi.c" "filter.c" "ftw.c"
"gc.c" "glob.c" "halfsip.c" "hash.c" "highest-bit-main.c" "highest-bit.c"
"highest-test.c" "isqrt.c" "itypes.c" "lex.yy.c" "lib.c" "lisplib.c"
"match.c" "parser.c" "protsym.c" "query.c" "rand.c" "regex.c"
"signal.c" "socket.c" "stream.c" "struct.c" "strudel.c" "sysif.c"
"syslog.c" "termios.c" "test.c" "tree.c" "txr.c" "unwind.c" "utf8.c"
"vecho.c" "vm.c" "y.tab.c")
OK, which ones are over 100000 bytes: 2> (keep-if [chain stat .size (op < 100000)] (glob "*.c"))
("arith.c" "eval.c" "ffi.c" "lex.yy.c" "lib.c" "match.c" "stream.c"
"y.tab.c") 1> (defstruct node ()
item
next)
#<struct-type node>
2> (new node next (new node next (new node item 42)))
#S(node item nil next #S(node item nil next #S(node item 42 next nil)))
3> (call .next.next.item *2)
42Meander [1] is also wonderful. Its unification-based approach makes for nice expressions of intent. Its strategy-based approach to rewriting [2] is more flexible than most common walker libraries, too.
[0]: https://github.com/redplanetlabs/specter/wiki/Specter's-inli...
[1]: https://github.com/noprompt/meander
[2]: https://github.com/noprompt/meander/blob/epsilon/doc/strateg...
Some production code:
(defn transform-tagged-values [x]
(sp/transform (sp/walker tr/tagged-value?) tagged-value->cljs x))
Give it a predicate for which values to transform, and a function to do the transformation. Couldn't be easier.When I started using it in one of my existing projects I was able to completely eliminate a few needlessly long and complex functions that were littered with comments and calls to helper functions. In their place are functions that are about 5 lines of code that barely even need a docstring because it's readily apparent what they do just by looking at the source.
A great example of why macros in Lisp are powerful, and how they empower you as a user even if you never write one.
also cf
Glom for Python: https://sedimental.org/glom_restructured_data.html
Hashdig in Ruby's standard library: https://ruby-doc.org/core-2.7.1/Hash.html#method-i-dig
I have been learning Clojure off and on for almost a year now. I gotta say that it has changed my mind to a "Aha, I got lisp now" moment. Working with it is a joy, especially it integrates so well with the JVM and all available Java libraries out there.
I can't believe I have missed Specter during my learning journey. How could I not find out about this soon enough. I mostly deal with static typed languages and seeing the primary use of map and keywords as main data structure scares me. Rich Hicky said not to put too much emphasis in what in the map but the data/keywords you need, kind of like you do not care what in the UPS truck as long as it could deliver your package, right? But, navigating maps and nested data structures around is the pain. Specter definitely easies that pain a lot now that I know it!
This is why I am grateful for hackernews. Once in awhile, browsing the site and discover something like this makes me rethink the ways I do stuff. It also reminds me that I could be missing a lots of similar goodies on my way learning Clojure. I am prepared to have me mind blown again!!!
Meander was the last one I can remember:
I wonder, is it possible to select some subset of a map? Say you have these paths:
(def paths [[:some :path] [:another :deeper :path] [:yet :another :one] [:yet :another :one :deeper]])
And select from a map these paths. You could do it with get-in, but maybe Specter can do it faster? I couldn't find a way to do it with Specter...
They really are the key to make immutable data structures as easy to update and work with as mutable data structures.