This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2017-06-03
Channels
- # beginners (446)
- # boot (16)
- # cljs-dev (2)
- # cljsrn (30)
- # clojars (2)
- # clojure (143)
- # clojure-finland (1)
- # clojure-greece (1)
- # clojure-nl (1)
- # clojure-russia (2)
- # clojure-spec (20)
- # clojure-uk (7)
- # clojurescript (167)
- # code-reviews (1)
- # community-development (12)
- # core-async (27)
- # cursive (3)
- # data-science (9)
- # datascript (2)
- # emacs (1)
- # graphql (46)
- # immutant (5)
- # jobs (2)
- # leiningen (1)
- # luminus (1)
- # lumo (76)
- # off-topic (79)
- # perun (2)
- # protorepl (33)
- # re-frame (21)
- # reagent (62)
- # ring-swagger (1)
- # rum (18)
- # spacemacs (6)
- # specter (4)
- # test-check (4)
- # unrepl (9)
- # untangled (2)
- # vim (4)
- # yada (1)
@noisesmith and I just posted a few versions of this very answer not even a few days ago. The log got eaten though.
Hint: you can do it with the rests
function. or the heads
function, in my last example above.
Here are the three examples I ended up with:
;; descriptive, transducers
(defn longest-increasing [number-sequence]
"Finds the longest subsequence of consecutively increasing numbers."
(let [longest #(apply max-key count %)
increasing? #(every? #{-1} (map (partial apply -) (partition 2 1 %)))
long-enough #(if (< 1 (count %)) (vec %) [])
rests #(take (count %) (iterate rest %))
exploder (comp (map reverse) (mapcat rests) (map reverse))
increasers (comp exploder (filter increasing?) (map long-enough))
increasing #(sequence increasers (rests %))]
(-> number-sequence (increasing) (longest))))
;; descriptive, thrush
(defn longest-increasing [number-sequence]
(let [longest #(apply max-key count %)
increasing? #(every? #{-1} (map (partial apply -) (partition 2 1 %)))
long-enough #(if (< 1 (count %)) (vec %) [])
rests #(take (count %) (iterate rest %))
exploder #(->> % (map reverse) (mapcat rests) (map reverse))
increasers #(->> % (exploder) (filter increasing?) (map long-enough))
increasing #(-> (rests %) increasers)]
(-> number-sequence (increasing) (longest))))
;; terse, thrush
(defn longest-increasing [x]
(->> (take (count x) (iterate rest x))
(map reverse)
(mapcat #(take (count %) (iterate rest %)))
(map reverse)
(filter #(every? #{-1} (map (partial apply -) (partition 2 1 %))))
(map #(if (< 1 (count %)) (vec %) []))
(apply max-key count)))
In this version, we use rests twice, once forwards, once backwards, to explode all combinations of the data
One improvement would be to make it so it doesn't generate the extra garbage structures that it eventually throws away, with the whole exploder process.
user=> (def edges "0 4\n0 2\n0 5\n1 0\n2 1\n2 5\n3 6\n3 1\n4 0\n4 5\n6 3\n")
#'user/edges
user=> edges
"0 4\n0 2\n0 5\n1 0\n2 1\n2 5\n3 6\n3 1\n4 0\n4 5\n6 3\n"
user=> (clojure.string/split-lines edges)
["0 4" "0 2" "0 5" "1 0" "2 1" "2 5" "3 6" "3 1" "4 0" "4 5" "6 3"]
user=> (map clojure.string/split (clojure.string/split-lines edges) #" ")
IllegalArgumentException Don't know how to create ISeq from: java.util.regex.Pattern clojure.lang.RT.seqFrom (RT.java:542)
every arg to map after the first needs to be a collection
if your function needs another arg, after the thing you map over, you need to make a lambda for that
How would you go about transforming this:
(["0" "4"] ["0" "2"] ["0" "5"] ["1" "0"] ["2" "1"] ["2" "5"] ["3" "6"] ["3" "1"] ["4" "0"] ["4" "5"] ["6" "3"])
Into something like
{:0 [4 2 5], :1 [0], :2 [1 5], ...}
?victora: Much belated, but happened to see this & thought it would be a fun little problem. It’s not very different from @noisesmith ‘s solution, but I would be inclined to do it like this:
(reduce (fn [m [k v]] (assoc m k (conj (m k) v)))
{}
'(["0" "4"] ["0" "2"] ["0" "5"] ["1" "0"] ["2" "1"] ["2" "5"] ["3" "6"] ["3" "1"] ["4" "0"] ["4" "5"] ["6" "3"]))
(and then if you want to convert them to ints, before or after the above, you can do
(clojure.walk/prewalk (fn [x] (if (string? x) (java.lang.Integer/parseInt x) x)) a)
)That does get them backward, but I’m assuming you just want a collection of them. I can add a step to switch them if you like.
1) you never need to refer to java.lang explicitly it's always in scope
2) prewalk is heavy handed when you already know the precise shape of the collection
3) (assoc m k (conj (m k) v))
should be written as (update m k conj v)
1) excellent point, it’s a bad habit of mine.
2) I disagree; prewalk
or postwalk
conveys the intention very clearly: you want to preserve the structure of this data, but perform some operation on each node.
3) Good point, thanks, although I can go either way on that one.
the reader accepts number keywords but they are technically illegal
you can just use numbers
anyway, zipmap
oh, you also want to split that series in specific places and parse the numbers...
so first you need a reduce to separate the keys and values
then apply hash-map
or you could combine them
oh, and apply concat to flatten it out a bit
Yeah, python equivalent of what I'm trying to do
m = {}
for p in pair_list:
if p[0] not in m:
m[p[0]] = [p[1]]
else:
m[p[0]].append(p[1])
return m
yeah - that doesn't use keywords or parse the strings, but OK
+user=> (->> [["0" "4"] ["0" "2"] ["0" "5"] ["1" "0"] ["2" "1"] ["2" "5"] ["3" "6"] ["3" "1"] ["4" "0"] ["4" "5"] ["6" "3"]]
(reduce (fn [m [k v]] (update m k (fnil conj []) v)) {}))
{"0" ["4" "2" "5"], "1" ["0"], "2" ["1" "5"], "3" ["6" "1"], "4" ["0" "5"], "6" ["3"]}
I didn't understand the task at first
that's the best way to do it - I understand now that I see your python version
(the code is almost the same if you are parsing too, it should be clear where the parsing goes)
->> is only in there to make the example a little easier to read, the input on one line, the code processing it on the next, it's not doing anything really
the one part that you can't just google / ask for doc for in the repl is the destructure, but if you google for clojure destructuring you should find something good on http://clojure.org
:thumbsup:
update accepts a map, a key, a function, and n args, changing the value under the key using the function and args
with the existing value as the first arg to said function
fnil accepts a function and a default value, and returns a function which when called with nil as its first arg, replaces it with the value
otherwise acting like the original function
fnil is mostly used with 0 (when you are using a map to accumulate a quantity) or an empty collection (when using a map to accumulate some collection type but don't want lists)
Pretty much what I came up with:
(->>
[["0" "4"] ["0" "2"] ["0" "5"] ["1" "0"] ["2" "1"] ["2" "5"] ["3" "6"] ["3" "1"] ["4" "0"] ["4" "5"] ["6" "3"]]
(reduce #(update %1 (first %2) conj (second %2)) {}))
but that returns backward lists
which is why I used fnil to get vectors in the right order
reduce is the thing that's bothering me now. I know what it does on paper but people use it to 'cheat' loops
@victora it's not a cheat, reduce is a looping structure
with the stipulation that you loop over elements of a collection
it even has early return
also, when your loop is accessing items of a collection, it's better to use reduce if possible, because it's faster
(as opposed to loop)
@victora another thing that helps a lot is reductions - it's like reduce but it returns a lazy seq of each intermediate state of the accumulator
your reduce's function takes two arguments - a map and a "pair" - and updates the map with this pair, correct?
because that's what reduce does, it iterates over lists
user=> (->> [["0" "4"] ["0" "2"] ["0" "5"] ["1" "0"] ["2" "1"] ["2" "5"] ["3" "6"] ["3" "1"] ["4" "0"] ["4" "5"] ["6" "3"]]
(reductions (fn [m [k v]] (update m k (fnil conj []) v)) {})
(pprint))
({}
{"0" ["4"]}
{"0" ["4" "2"]}
{"0" ["4" "2" "5"]}
{"0" ["4" "2" "5"], "1" ["0"]}
{"0" ["4" "2" "5"], "1" ["0"], "2" ["1"]}
{"0" ["4" "2" "5"], "1" ["0"], "2" ["1" "5"]}
{"0" ["4" "2" "5"], "1" ["0"], "2" ["1" "5"], "3" ["6"]}
{"0" ["4" "2" "5"], "1" ["0"], "2" ["1" "5"], "3" ["6" "1"]}
{"0" ["4" "2" "5"],
"1" ["0"],
"2" ["1" "5"],
"3" ["6" "1"],
"4" ["0"]}
{"0" ["4" "2" "5"],
"1" ["0"],
"2" ["1" "5"],
"3" ["6" "1"],
"4" ["0" "5"]}
{"0" ["4" "2" "5"],
"1" ["0"],
"2" ["1" "5"],
"3" ["6" "1"],
"4" ["0" "5"],
"6" ["3"]})
nil
see, reductions shows each step
it doesn't take elements two by two, it takes them one by one, and combines them with an accumulator
if you don't provide an accumulator, the first element of your collection is used implicitly
Okay, now I understand the difference. Reduce behaves differently depending on the number of arguments passed
only in terms of the accumulator and the first element of the coll
the behavior is only trivially different
avoid read-string
on the jvm, use Long/parseLong
read-string allows arbitrary code execution, and it's a bit overpowered when you know all you want is to parse a number of a known type
user=> (Long/parseLong "3")
3
user=> (map #(map Long/parseLong %) [["0" "1"] ["0" "2"]])
CompilerException java.lang.RuntimeException: Unable to find static field: parseLong in class java.lang.Long, compiling:(NO_SOURCE_PATH:5:7)
methods are not first class
#(Long/parseLong %)
functions are actually objects with an invoke method on it 😄
you can use fn
, since you can't nest #()
or, you can just use (fn [m [k v]] (update m (Long/parseLong k) (fnil conj []) (Long/parseLong v)))
since you know the precise structure and it's small
using fn to transform a method to first class is standard procedure or considered dirty?
it's the only way to do it
oh, there is that
@john if you macroexpand, it creates an fn 😄
+user=> (macroexpand-1 '(memfn length))
(clojure.core/fn [target58] (. target58 (length)))
user=> map #(map (fn [x] (Long/parseLong x)) %) [["0" "1"]]
#object[clojure.core$map 0x16c069df "clojure.core$map@16c069df"]
#object[user$eval45$fn__46 0x2a7ed1f "user$eval45$fn__46@2a7ed1f"]
[["0" "1"]]
where did I go wrong?open paren?
that's a matter of preference, the repl can do a lot on its own
I rely on load-file, clojure.repl/doc clojure.repl/source, the :reload optional arg to require
and I don't use editor/repl integration
but if you like real IDEs cursive is great
LazySeqs, yeah
is the repl what I get by simply using the command "clojure"? Cause that thing is awful lol
but unless you are looking up by index, you probably don't need to care
you can also use leinengen (a project manager) that gives you a repl with your project deps
@victora you can use rlwrap
for that (that's what I use when not working on a project)
Ok, next is an important question. How would you indent this piece of code?
(defn graph [e]
(reduce (fn [m [k v]] (update m k (fnil conj []) v)) {} (map #(map (fn [x] (Long/parseLong x)) %) (map #(clojure.string/split % #" ") (clojure.string/split-lines edges)))))
(defn graph [e]
(reduce (fn [m [k v]]
(update m k (fnil conj []) v))
{}
(map #(map (fn [x]
(Long/parseLong x))
%)
(map #(clojure.string/split % #" ")
(clojure.string/split-lines edges)))))
I would never nest that many maps btw
(defn graph [e]
(reduce (fn [m [k v]]
(update m k (fnil conj []) v))
{}
(map (comp #(map (fn [x]
(Long/parseLong x))
%)
#(clojure.string/split % #" "))
(clojure.string/split-lines edges))))
also there's a function called transduce, for when you are doing a reduce but need to do a stream transform on the input data
(defn graph [e]
(transduce (map (comp #(map (fn [x]
(Long/parseLong x))
%)
#(clojure.string/split % #" ")))
(fn [m [k v]]
(update m k (fnil conj []) v))
{}
(clojure.string/split-lines edges)))
@victora (comp f g) is like (fn [x] (f (g x)))
like the dot operator in algebra (composition)
It actually easy to translate comp
ed transducers as a ->>
thrush, if that helps you think about it
right, but there's no comped transducers here
there are comped functions in a map though
which map are you talking about? {} is a persistent hash map, it has Log(n) update
but it's actually Log32(n) or something
Can I make it not persistent if I need the performance? Or should I just use a java lib then?
it's close enough to constant time that I've only had it as a bottleneck once, and that was mostly because of the whole immutability thing making so much garbage
we can use java hash maps, measure before doing that optimization, in years of usage I've only had to do that once
and that was because I was doing a graph analysis that took nearly half an hour
(using an algorithm that did lots of hash-map updates of course)
right
sure - clojure doesn't technically interpret, the only way to run clojure is via the compiler
as far as that distinction matters
but yeah, it would be a question of getting a PushbackReader from the file, and doing a loop of reading a form and printing the output of evaluating the form
right -but not only that, it doesn't have an interpreter, the only way to run clojure code is to create bytecode and run it
(on the jvm at least)
most of the time that distinction doesn't matter, but just being clear
which is weird considering how easy it is to write interpreters for functional languages
but clojure avoids special cases
for example, when you load a file, the same exact code paths are run as if you typed the same thing into the repl (with very minor differences, a few booleans that get set for class file generation on disk)
which can surprise people - they expect to be able to use a definition higher in the file then they specify it for example
but clojure is following the same rules as the repl - if you haven't run it yet, the definition doesn't exist and it errors
but it avoids having to remember all kinds of interpret vs. compile special cases (which in many lisps turn into two different languages over time)
because clojure is intended to be relatively efficient
there's lots of things that could be a little more normal, or friendly, but clojure opted for the thing that performs well without introducing complexity (if possible)
{0 [4 2 5], 1 [0], 2 [1 5], 3 [6 1], 4 [0 5], 6 [3]}
This is the map created by our code. Why isn't it shown with the ':' before keys?@victora keyword is a not a special "this is a key in a map" data type
it's a special variation on a symbol
in json the : is not part of the data, it indicates a key/value pair
in clojure :foo is a specific data type, a keyword, it can exist outside hash maps, and all types are allowed as hash map keys
keywords are especially useful as hash-map keys because when used as functions they attempt to look themselves up in their arg
but they are not needed - if your data is numeric, just use numbers 😄
symbols also look themselves up as args, but they are mainly used in constructing macros or looking up namespaces or values in namespaces (which is actually what they do in macros...)
And because keywords are constructed with symbols, symbols cannot start with a number, therefore some things throw on :1
Okay, what I'm trying to do may be very dumb and unorthodox, but I'm trying to code algorithms I'm familiar with in clojure, to learn you know. How do I deal with needing a fixed-size mutable array in clojure? e.g. bool visited[n]
if it needs to be mutable you might want to learn an immutable alternative as part of learning clojure
you can use mutable types, the java arrays for example, but this is abnormal and only done in extreme cases
in general, until profiling shows you that your data updates are a bottleneck, use the default clojure collections and replace mutation with recursion that sets a new binding
@john using transient as if it actually mutated the collection is buggy
it's not reliable, when it works it works accidentally
the correct way to use a transient is to always bind the return value, just as you would with an immutable object
right - by about 15%
use things that use transients implicitly (into) because why not, but the small speedup is rarely worth the 15% speedup
(when using them directly)
I'm thinking about the DFS code, ok? I need to mark a node visited whenever he is. I could do that with a map, and the lookup/update time shouldn't take much longer than O(1). It seems like overkill though
the usual thing is to use immutable data
use immutable data, if profiling shows the immutable updates are the bottleneck, use mutable data
if you do it right the translation is trivial
right, we would do this with a recursive function call that takes visited as an arg
there's a proof out there that every mutable algorithm can be replaced by an immutable one where every accessed mutable data item is replaced with an extra argument to each function that uses it (and re-bound based on the return value)
Vector being immutable means everytime I change something I'm actually creating a new one, like strings in java?
no, they are persistent
which means they share structure
since you know that nobody else can mutate the vector, you can reuse the parts you don't update
oh, that's a good point yes (or clojure.walk/walk that can combine pre and post walk actions)
or tree-seq if you just want to hit each node of a tree
@victora tree-seq and clojure.walk come with clojure and you can see source with the source
function in the repl also
on top of that, clojure.jar can be unzipped and you can read the clj files inside
or just browse github of course
@victora I bet what you are actually looking at is a multi-arity function
just a guess
No, it's about this https://clojuredocs.org/clojure.core/do
yes, function bodies always have an implicit do
but clojure.core doesn't use that, which is why I thought you were mistaking a multi-arity function
well - rarely I guess
If I'm calling 3 times dfs from inside one instance, I need to combine the 3 returns right?
In one call to dfs I may call dfs multiple times. All of them are "contributing" and changing the visited array in my python implementation.
For the sake of learning the language, I'm starting by just marking the reachable nodes
dfs
(some #(= % :a) (tree-seq coll? seq [[:b :c] [:d :e :f [:g :a] :a]]))
true
if you need to accumulate state, use reduce over the tree-seq
or you can use a zipper for more elaborate traversal - clojure.zip
but this isn't the easy way to get into clojure - some things that are very tricky in other langs are simple here, and some things easy in others are more complex in clojure
unless you have a pressing reason, I don't think starting with tree walking and marking nodes will be rewarding at all
as an intro to the language at least
I mean, we have some nice tricks but they will look super weird
right, we have easier ways to do this stuff but it won't look like a dfs
I mean - it is actually a dfs 😄
@victora yes they are, I use graphs as my primary domain object, in clojure I always turn them into an adjacency list
(my day job is messing with graphs in clojure)
yes but I'd never do it that way in clojure except as a last resort
(boolean-array n)
I've never used that
but it exists
I would map a hash-map from node id to a hash of properties, including visited
@akiroz right, that's exactly what it is
in some cases I might make the properties part of my adjacency list, sometimes a separate map with the same keys
@victora yeah, they are the easy way to do things in clojure, especially if you need to do lookups
because hanging ) are noise
it's a lisp tradition going back to the '50s
yeah, I'd never rely on metadata for this sort of thing
for example I can't put metadata on arbitrary data that I use as graph identifiers
but I can make a hash-map from identifier to properties
@akiroz sure, but this use case of marking a node visitor, most of the good graph node id types don't accept metadata
@victora thinking a moment longer, I would actually use a hash-set of node-ids when keeping track of what I have visited
like, that's literally what I pass along in my traversals for cyclical data
for non-cyclical, I stick with simpler things though
hash-set means you can check if it's in there as fast as you could lookup in a map, right?
right, exactly
a hash-set also acts as a function that returns its arg if the arg is present in it
otherwise nil
so really, they are what we would use instead of indexed boolean arrays for checking membership/non-membership
unless doing crazy optimizations
we have clojure.lang.PersistentQueue
it's a little weird to use, but it's good
+user=> (-> clojure.lang.PersistentQueue/EMPTY (conj 1 2 3) (pop) (conj 44 55) (pop) (seq))
(3 44 55)
just be aware that the only operations that preserve the type of the queue are peek, pop, conj, and others built on those (like into)
I had a bug in my app where someone called rest on a queue, returns a list, and turned a fifo into a lifo
and it was subtle because lists also implement stack so peek and pop work on them
well - peek doesn't preserve type (it returns one element) but it's meant to be used with the stacky types like queue and list
exactly
unless only working on side effects and you don't want to short circuit - in that case doseq also works
but if building a result functionally, reduce is usually what you want
there's also for
which is a list comprehension, which is the right thing for lazily generating a series from N input series
but that's probably not what you want here
that's what for is - I don't think it maps 1:1 but it does most of the stuff
it also accepts :let and :while keys
right - often my reduce is surrounded by another form that grabs what I really want out of the accumulator
with transduce, the reducing function can accept a one-arg arity that is used as the "finalize" on the accumulator value
Exception in thread "main" java.lang.ClassCastException: java.lang.Boolean cannot be cast to clojure.lang.IFn
you can use not
as the update function
because (update x y true) tells it to use true as a function, which is invalid
but not works, and returns the right value
it's weird but it works
not nil returns true
update gives you nil if the thing is not present
so I think you actually just want assoc
or, use a set instead of hash-map and use conj
where "in the set" translates to true
oh, I would definitely use assoc
with true rather than update
with not btw
(if going that route)
awesome
once it comes naturally, immutability has some nice side effects though 😉
eg, making concurrency and parallelism a lot easier to get right for starters
we don't really use either
refs / atoms do an optimistic update followed by compare and swap without locking
you do need to watch out for side effecting functions in your update code, but that's easy enough to avoid
Thanks for the help @john @akiroz and @noisesmith . I'm gonna get some sleep, but I'll come back with more questions 🙂
:thumbsup:
use brings in symbols unqualified, require only brings things in via :as or :refer keys, otherwise you need to specify the whole namespace to use it
the strong preference in the community is to use require with :as instead of use or refer
but is there a way of requiring a namespace without having to prefix it? Like in python "import library as *" lets you use functions from that library as if they were part of your current program.
I mean that works with use
so I'm wondering if it can be done with require
.
This is mostly for quick tests in my repl
that's what use is for
but don't do this in code, it makes things harder to read
if you don't want the :as feature, or to limit which symbols get referred, there's no reason to use require instead of use
Yes but I understand what you mean that in real code people should know where I'm getting those functions from
If you need a specific function from a namespace: (require '[nspace.nfile :refer [specific-function]])
But doing (require '[nspace.nfile :as nf])
and then (nf/specific-function ...)
will eliminate a whole class of errors related to shadowing variables, etc.
"I never would have thought another namespace would also use the name specific-function
"
They're usually compile time errors, so it's not that big a deal. But just settling on using :as
is the simplest rule of thumb.
the main problem with use and the :refer feature of require is when reading code, or trying to refactor
I only partially agree with that argument. I think that if a particular namespace or set of functions aren't exposed to downstream users, but are only for the purpose of other functions within a given lib, cluttering up the whole namespace with tons of prefixes doesn't make it more readable.
that's the opposite of all my experience
require never exposes anything to downstream users
I mean, exposure in the sense of downstream users needing to read the upstream code and actually understand it.
I don't want to play guessing games figuring out where the hell a function definition came from when reading the code
If some util/read
function is used everywhere in a lib... I think we'll get it pretty quick that that :refer [read]
at the top is what it is.
as someone who has to read and maintain code other people wrote, that kind of thing just bugs me
I want the namespace that something came from to be 100% unambiguous
without having to constantly jump to the ns form and look at the refer blocks
having 50 util/
s up and down a file seems like too much to me. Now, if it was read-string
that could def be ambiguous. Yeah, annoyance is a very valid argument and I may be shying away from :refer
too, just because of culture, mostly.
@vitruvia with :as, so (ns my.ns (:require [some.other.ns :as other])) (other/foo ...)
You could do (ns my.ns (:require [some.other.ns])) (some.other.ns/foo ...)
Your code might get bloated though.
it's also a bad habit because it can lead to forgetting to require the ns (it works anyway, as long as some other ns required it...)
so you get no error during dev, but then with a fresh restart it errors, or later when you change the other namespace it errors
but the specific problem is it does work even without a require in your ns... but by accident. That's the real danger.
see for example people that think that clojure.set is always in scope, because lein's repl requires it
(or pprint for that matter)
There's also that issue I ran into recently with :refer
in CLJS, where if you want to require multiple different implementations of a particular protocol, each instance method is going to have the same name, which won't work with :refer
.
you should never be getting the instance method from the implementation
that's the wrong way to use protocols
the method comes from the ns defining the protocol itself
that's kind of the point of protocols, it's one method that does different things on each arg depending on how that arg extends the protocol
I was making a type that took multiple objects of different types during construction. I wasn't doing the vanilla protocol thing. Sort of an implementation inheritance. So I think I needed to. But I'd have to go back and look at the code. You helped me with it at the time.
if you had two protocols that had methods of the same name, you could have an issue like this... but you can't even require a protocol method from an implementation namespace last I checked, it has to come from the ns defining the protocol
@john full example demonstrating what I'm saying
+user=> (ns some.proto)
nil
+some.proto=> (defprotocol IFoo (frob [this]))
IFoo
+some.proto=> (ns some.impl (:require [some.proto :as p]))
nil
+some.impl=> (deftype Foo [] p/IFoo (frob [_] "hi"))
some.impl.Foo
+some.impl=> (ns some.client (:require [some.proto :as p] [some.impl :as i :refer [frob]]))
IllegalAccessError frob does not exist clojure.core/refer (core.clj:4201)
+some.client=> (ns some.client (:require [some.proto :as p] [some.impl :as i]))
nil
+some.client=> (p/frob (i/->Foo))
"hi"
hi all, trying to set up nightcode for doing some arduino hacking with my son. can get the project to run in emacs. but on nightcode i do get the repl working. but when evaluating the lib for arduino on core.clj i get a filenotfoundexception on classpath. when trying to load the firmata lib. ie.
(require '[firmata.core :as fm])
just to share: chatted with Zach @U080181PF about this and learned that instarepl in nightcode can't access third party libraries but that nightlight's instarepl doesn't have that restriction. Checked out Nightlight and tried it as well. It's awesome and when evaluation of just a single expression is supported I think that might be the right tool for this project!
are you sure the repl is using your project deps?
@noisesmith That's right. I remember now.
what does (System/getProperty "java.class.path") show?
it should show all the jars you depend on, plus your source directories
@sakalli sorry, if it wasn't clear, that question was directed to you ^
yes cheers @noisesmith checking as we speak.
cant find the firmata dependency in classplath but the require does evaluate in repl:
@sakalli one thing that looks weird - it almost looks like your project.clj is inside the target directory? it could be I'm misunderstanding the nightcode UI
see what you mean, but no. its just the ui. target and project.clj on the same level.
it seems very odd to me that the require would work in the repl and not your source file
within the same environment
+user=> (ffirst (drop-while #(apply not= %) (partition 2 1 (iterate #(pprint/cl-format nil "~r" (count %)) "one"))))
"four"
fun fixed pointit's not obfuscated!
for each input, it counts the letter's and prints it in english
it stops when two in a row are the same - a fixed point number that has as many letters in it as it denotes
if you just looked at the iterate, it would get to "four" and just repeat that - because "four" has four letters
+user=> (->> "one"
(iterate #(pprint/cl-format nil "~r" (count %)))
(partition 2 1)
(drop-while #(apply not= %))
(ffirst))
"four"
+user=> (take 10 (iterate #(pprint/cl-format nil "~r" (count %)) "one hundred"))
("one hundred" "eleven" "six" "three" "five" "four" "four" "four" "four" "four")
+user=> (take 10 (iterate #(pprint/cl-format nil "~r" (count %)) (pprint/cl-format nil "~r" (rand-int 1000000000))))
("five hundred seventy-three million, nine hundred ninety-seven thousand, eight hundred ninety-six" "ninety-six" "ten" "three" "five" "four" "four" "four" "four" "four")
so clojure already has a function to print numbers in english? I remember doing dictionaries to solve a similar thing in python
cl-format is a port of the common lisp format function, which can do a lot of crazy stuff, including printing english names for numbers, roman numerals, complex turing complete formatting rules...