This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2016-03-02
Channels
- # admin-announcements (9)
- # alda (21)
- # announcements (1)
- # beginners (68)
- # boot (241)
- # braid-chat (18)
- # cider (32)
- # cljs-dev (4)
- # cljsrn (11)
- # clojure (60)
- # clojure-dusseldorf (1)
- # clojure-germany (1)
- # clojure-poland (212)
- # clojure-russia (64)
- # clojure-sg (10)
- # clojurescript (212)
- # core-async (1)
- # css (14)
- # datomic (1)
- # emacs (9)
- # funcool (2)
- # hoplon (18)
- # jobs (1)
- # ldnclj (1)
- # lein-figwheel (5)
- # leiningen (3)
- # om (190)
- # onyx (46)
- # parinfer (13)
- # proton (3)
- # re-frame (7)
- # reagent (10)
- # ring-swagger (2)
- # slack-help (3)
- # specter (1)
- # yada (31)
@swizzard: I learned how to use enlive from https://github.com/swannodette/enlive-tutorial
Is there a better way of saying (comp #(max 0 %) dec)
for decrementing but never going negative?
@slester: Looks fine to me. I might write it like #(max 0 (dec %))
, but it’s the same thing essentially.
it doesn't necessarily have to be 'shorter', I just want to make sure I'm writing things in the community-accepted way
ok! question two. I have a function that I want to be able to deal with both a list of ints and a single int. Is there a nice way of making the int a list?
I was just going to reduce over the eventual list, there's no special behavior for the single int
@slester: I try to avoid making functions that work on both types like that. Pretty much for the same reasons laid out here: https://stuartsierra.com/2015/06/10/clojure-donts-heisenparameter
Is there a core library function that implements the following idea (which is fairly close to a common use of cond->
, in some sense):
(defn magic
[v p? f]
(if (p? v)
(f v)
v))
It would let me do:
(magic "" empty? (constantly "Default”))
Or
(defn abs [x] (magic x neg? -))
We ended up writing a condp->
macro for that -- like cond->
but threads through the predicate as well.
(condp-> v p1? f1 p2? f2)
@seancorfield: Ahh… that makes me feel better at least. (It is not just me that keeps encountering this code pattern.)
We have condp->>
too (of course).
(This has been bugging me. I think I encounter the desire for condp->
once every few days. Maybe it’s just me.)
We have maybe one or two uses in 30,000 lines of code...
@seancorfield: Ahh. Thanks! I might be approaching things wrong then. I need to re-wire that miswired part of my brain.
It's entirely likely we could use it a lot more than we do -- we just haven't felt the need. And maybe that's a "yet". As we improve the idiomatic level of our code, maybe we'd reach for it more. I don't know.
Is there something similar to Maybe or Either in Clojure? In Haskell we were able to use those types in order to encode possible errors in the actual type system rather then relying on a mechanism such as try catch. For example if you have a divide function, you could accept two numbers and return a “maybe number”, meaning if the denominator is zero you would return “nothing” otherwise you would return “just the (numerator / denominator)” That way other functions that call your divide function will be aware that things might go wrong and must handle (usually using pattern matching) both cases.
In general in Clojure you would either return nil
(meaning Nothing) or perhaps use a sequence with 0 or 1 elements.
The idiom of nil punning makes nil
very common as "Nothing".
I'm not sure how that's a "maybe" number. If the denominator is zero, the function returns nothing, otherwise returns the product? That sounds like a simple if-then with a dubious return. After all, if the function returns nothing how does the caller check for this? Nil works out as a much better return value, and no one ends up waiting forever.
(defn divide [x y] (if (zero? y) nil (/ x y)))
Since then you can do (if-let [v (divide a b)] (… v …) "No value to do something with")
But of course you have to know you’re dealing with a nilable value…
Although I’d probably just let the divide-by-zero exception happen and propagate unless I had a good reason not to 😸
is there a way to take the parameter of one function and pass it into the parameters of another function in another namespace?
@adamkowalski: Rather than exposing exceptions to calling code I sometimes use golang's idiom, returning a tuple of [value ok?], which is easy to destructure. But generally speaking there isn't any checking of return value types of Clojure fns ahead of runtime, so there isn't really a way to help (or get help from) the compiler in the way one can with Maybe.
thanks for all the ideas, its given me some things to think about
I do have a few concerns with some of these concepts though
@seancorfield: you suggested returning nil from the function, which makes sense but then every function would need to check if the value that got passed in is nil before doing the next thing, which is something I would like to avoid
@adamkowalski: Understood — but since there’s no type system per se, and nil punning is idiomatic, testing for nil
(or just plain ol’ handling it) is common practice.
Many built-in functions behave in sensible ways when given nil
.
right, it seems like the issue is that because everything is dynamic it requires a different mindset then other languages
Yes, re: different mindset.
like for example if you used function composition how do you “know” that two functions could work together?
in Haskell if you have a function “f :: b -> c” and “g :: a -> b” you could create function “h” which is the composition of f and g
which would then have the type “h :: a -> c"
but if everything is dynamic this seems like you would need to use perhaps a series of pre and post conditions to ensure that the output of function g matching the input of function f right?
and if g can either return a number, or nil as in the example you provided above, f would need to not only look for a number but must also check for a nil value
As I said, nil punning is idiomatic. It’s a very different approach to Haskell (or Scala or…).
hence why in haskell you could have g :: a -> maybe b and f :: b -> maybe c then h uses a kliesli (i probably spelled that wrong) arrow to compose f and g
making a new function which goes from a to maybe c
ok I will look more into nil punning.
I’m not saying nil punning is the "right way" to address your numeric division example — I’d rely on exceptions there personally — but instead of Maybe and Monads, Clojure tends more to nil
and punning.
adamkowalski this is a good post about nil punning http://www.lispcast.com/nil-punning
thanks for the link, it seems like an interesting read
it seems like it is addressing exactly what I was afraid of haha, I have always had poor experiences with null pointers before in other languages
@adamkowalski: it's exactly right to look at this from a function composition perspective; with Clojure, that turns into adopting a data flow mindset. For data flow of entities (rather than reduction/folding operations on collections) Clojure has a number of "threading" macros- here's some good coverage: http://www.spacjer.com/blog/2015/11/09/lesser-known-clojure-variants-of-threading-macro/
some->
allows pipelining of functions / values where nil
is an "expected" result so that’s a bit like monadic operations with maybe values in Haskell (if you squint hard).
But built-in functions that accept collections pretty much all accept nil
and treat it like an empty collection which also allows pipelining. And often the empty collection and nil
are viewed as "the same" (consider seq
which accepts nil
and ()
and produces nil
for both). And the very fact that nil
is considered as false helps with a lot of this too.
I find I don’t hit NPEs in Clojure very often — certainly not compared to when I was working in Java or Groovy (or even in Scala!).
yeah it seems like all these different threading macros can help out quite a bit to make your code do similar things to what I was talking about earlier
thats what I was hoping for, not necessarily to do the same thing in Clojure that I was used to in Haskell (because then why not just use Haskell), but rather to learn how Clojure developers deal with such problems and solve them in their own unique ways.
but I wonder if there is a way to somehow incorporate transducers into there somehow
because with the cond->> example they show in that link they are essentially checking whether or not they want to map or filter or sum the collection, but they might do all of them or none of them
It seems like it would be better to somehow use a transducer and function composition using a series of when statements
like instead of (defn process-collection [col use-map? use-filter? sum?] (cond->> col use-map? (map (fn [x] (* x 5))) use-filter? (filter (fn [x] (< x 25))) sum? (reduce +))) (defn process-collection [col use-map? use-filter? sum?] (into [] (comp (when use-map? (map (fn [x] (* x 5))) (when use-filter? (filter (fn [x] (< x 25)))) (when sum? (reduce +))) col))
or something like that
actually wow, some-> and some->> literally do everything I want. thanks a lot guys!
(as suggested on #C03RZGPG1 : try #C0AB48493 )