This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2018-11-13
Channels
- # aleph (2)
- # announcements (1)
- # beginners (133)
- # cider (29)
- # cljdoc (9)
- # cljs-dev (2)
- # cljsjs (3)
- # cljsrn (1)
- # clojure (146)
- # clojure-dev (26)
- # clojure-europe (3)
- # clojure-italy (26)
- # clojure-japan (6)
- # clojure-nl (76)
- # clojure-spec (4)
- # clojure-uk (42)
- # clojurescript (17)
- # cursive (43)
- # datascript (1)
- # datomic (28)
- # emacs (4)
- # figwheel-main (13)
- # fulcro (26)
- # hyperfiddle (2)
- # jobs (9)
- # jobs-discuss (6)
- # leiningen (1)
- # mount (5)
- # onyx (8)
- # pathom (5)
- # pedestal (2)
- # re-frame (52)
- # reagent (21)
- # reitit (58)
- # ring-swagger (24)
- # shadow-cljs (95)
- # sql (14)
- # test-check (10)
- # yada (18)
@jpsoares106 4clojure is nice for doing various exercises but for some more curated exercises with, in turn, more curated solutions, I'd recommend https://github.com/gigasquid/wonderland-clojure-katas
@jpsoares106 If you're interested in something more introductory, when I was first learning I started with https://github.com/functional-koans/clojure-koans before moving on to those katas. I don't remember seeing viewable solutions for the koans, but it's set up so you can easily run through them iteratively, with all the tests already set up (whereas the katas have links to solutions you can view, and the first one or two have tests written for you, the later katas require you to also write the tests)
I have not used Lighttable before, so can't help you there. What kind of system are you using? (e.g. Windows, Mac, Linux?)
Does Lighttable have a Clojure REPL built in? If so, is it not doing what you want, and that is why you want to run lein repl?
It should certainly be possible to run a lein repl separately from Lighttable, too, if you wanted to, from a Windows command line.
I will probably not be awake much longer here, but wanted to mention that there is a #lighttable channel, too, but you are certainly OK to ask here as a beginner. I do not know how many people are in the #lighttable channel. I am not trying to scare you off, but do realize that because Lighttable development stopped a year or two ago, it may not be the most often used development environment for Clojure. It does have some nifty features, that is certain.
how do I check if a vector of booleans are all true? (apply 'and [true false true])
doesn't seem to work
If you want true as in exactly equal to true, use (every? true? [...])
. But if you want truthy, as in true if everything is not nil or false, you can use (every? identity [...])
It’s a macro
Even worse, 'and
in that example isn't a macro, it's a function that attempts to look up a symbol and optionally return a provided default if not found
For the right input it even looks like it works ('and true true)
(every? identity [true false true])
is probably the best answer here
So I was looking at this because I had implemented all-true?
and any-true?
using reduce before. This every trick is obviously a way to implement all-true?
, but how would you go about any-true?
?. Thinking about it mathematically, all-true?
is basically, (not (any-false? ...))
.
(some ...)
doesn’t completely cut it because it returns the first logical true item or nil
maybe its me really wanting true/false instead of truthy/falsy
you can use boolean
instead of identity
(some true? coll)
sounds like what you're looking for, if you want to exclude truthy values that aren't true
.
(boolean (some boolean [false false]))
if you are literally using booleans, then yes true?
might be useful
Yeah right
(every? identity [1 "abc" true])
is true, so then (boolean (some identity ...))
would be the most faithful counterpart
(Going from the domain of a collection of truthy/falsy values to a true or false)
I prefer (every? true? [true false true])
since it's more explicit. Also, it depends if OP wanted truthy or true.
My solution accepts truthy/falsy values and will only output true/false values 🙂. Kinda like: “Be liberal in what you receive and strict in what you send”.
Is there a term for the idiom of returning a truthy value instead of returning true? I found "nil punning" for the opposite idiom, but I can't find "true punning" or "value punning". I'm wondering when it's best to return the truthy value vs returning true, and I want to read more about this practice. @U064X3EF3
in the core api, that’s usually referred to as a “logically true” value
but I can’t say I have anything for you to read about it
Tough to google for "logically true" haha
prob the best “reference” is the nil
section at https://clojure.org/reference/data_structures#nil
I've come across the idea that fns ending in ?
imply a boolean return. Is that the common practice in core code?
And I've seen reference to this idea in "The Joy of Clojure" but I don't have the book so I can't check. If the book talks more about this kind of style decision maybe I'll pick it up.
these are often called “predicates” too
*reference to the fact that the idea is discussed in "TJoC"
you should pick up Joy of Clojure anyways :)
A couple good reads I found: https://lispcast.com/nil-punning/ https://danielcompton.net/2017/03/31/clojure-nil-predicates The issue in the second link was indeed fixed to restore consistency across predicates returning true/false, so it sounds like about as consistent a rule as it can be.
Hmm my biggest objection to nil
is not that it doesn’t behave, but that it is a silent side effect of anything I do
when, in haskell, a function returns Maybe a
, I know damn well that it can fail
Very much a fan of Rust consistenly marking functions that can fail with a Result
type
So, imagine you didn't have static types. Which is the case in Clojure. Now all functions can fail abruptly, those would still throw failure exceptions like say OutOfMemory. But now what about errors that are expected. Like illogical input, or things like can not compute. What would you want to happen?
Let's go back to types. Why is there even errors? Because the type system isn't powerful enough. So a function returns a Maybe because you actually can't guarantee that it will work for all input.
Now in Clojure, you have no types. Thus no functions are guaranteed to ever work for all input.
Okay, so what do we do? Well, we make all output from functions be a union of wtv the function can logically return and nil.
Now that we recognise that all functions can return either Nil or wtv they logically return, you also need to recognise thus that every function composition will pipe a result of Either Nil or the logical result to the input of another function.
Thus, you design all functions to handle Nil input. And BOOM, you now have Nil Punning
Given functions which handle Nil input and can return the logical result or Nil, you can now compose freely and everything will just work!
So what limitations does this have? Well there are two limitations to this in Clojure. First one is Java interop. Java doesn't do Nil punning, it throws exceptions instead for most things. So now you need to deal with both Nils and Exceptions for most contexts, which is more tedious. Second is that Nil doesn't tell you much of the root cause. So if you wanted to handle different type of errors in different ways, Nil isn't powerful enough. It would be pretty awesome if you could attach error types to Nil. In which case, it would be a lot more like things that return Error. But again, Java also return null sometimes. And so all this interupness means we're stuck acknowledging both Nil and Exceptions. So to me, it goes like this: Is there only one way to handle non logical result? Then return nil. If there are more ways, throw exceptions. Always design functions that handle Nil input, and always make sure you try/catch calls to functions that can throw.
well yeah clojure doesn’t have a formal type system but you can still design by contract. If you promise that a function accepts x, y and z, and the pledge that it returns some maybe record. That would work. Not that the contract is checked ever, but it would make me as a consumer of that function aware of possibility of failure.
Also, in haskell, Maybe a
is Functor/Applicative/Alternative/Monad so you get fail-fast for free
Java interop is indeed still tricky, because well, you have no control over whether a function returns nil or throws an exception
In my experience, when a nil travels through my code, it ends up crashing somewhere :’)
Much rather have to acknowledge that some code can fail, than have a nil that goes into another function that does something with that nil and returns nil and …
I don't think you understood me. My point is that every function in Clojure returns Maybe a
Where you either get "a", where a is not explicitly defined because we are in a dynamic context, but it can be thought as the implicit logical type of values you expect the function to return.
yes, but having all functions make no guarantees about whether it will return something defeats the point IMO. I personally, but maybe thats me prefering static typing, like to seperate ‘functions that can fail’ from ‘functions that cannot’.
Meh, maybe I have to embrace it a bit more
I mean, prefering sure, but what I'm trying to say is that you just can't have a similar thing in a dynamically typed context, because there's nothing to make such guarantee. So there's no difference between the doc-string saying Returns a or nil, versus Returns Just a or Nothing.
Every function you see that mention they return nil in the doc-string is effectively a function that is declaring to you it returns a Maybe of a
myDiv2 :: Float -> Float -> Maybe Float
myDiv2 x 0 = Nothing
myDiv2 x y = Just (x / y)
(defn my-div-2 [x y]
(if (zero? y)
nil
(/ x y)))
Those are the sameYeah sure. Cats has an either-type that you could return and make it a convesion to forbid methods returning nil
but there is certainly no type checker to save you
And then values are returned in Left
or Right
, so client code needs to treat it as such before it can do anything.
You are probably right tho, its just a different way of thinking that I am not used to
Well, that's the thing, sure cats has a Maybe type, but it really just feels useless, like extra ceremonious. And cats acknowledges that also, by having nil be equivalent to Nothing.
So in cats, nil is Nothing. And you can neither enforce people check for nil or Nothing, neither can you specify your function returns a Maybe since there's no return type signature.
Yeah, but with Haskell being my previous functional programming language, I have grown used to that ceremony. I really just have to embrace the dynamic nature of Clojure more
Ya, it takes a bit of adjustment for sure. And then there's personal preference, how your brain thinks, etc.
I think it could help if you start thinking about implicit return types. Such that say first
returns nil if you give it an empty collection.
In haskell, you'd say first returns a Maybe a.
In Clojure, first returns a Maybe a also, where its Just the first element or Nothing (aka nil).
The implicit nature though means it's up to you to realize that first can return Nothing (aka nil), and make sure you account for it and check that what you got isn't nil
Now I think the difference is that in Clojure it's not Monadic, though libs like cats can make nil Monadic. What Clojure does is simpler, it allows nil to be composed normally, but most functions just pass it through, thus short circuiting on a nil. Where in haskell or with cats, you'd use the Monadic bind to compose the functions instead. Meaning other functions don't need to handle nil input, the Monad will deal with that and short circuit the chain for you.
It’s my hope that a future version of ClojureScript will be able to compile
(subs x 0 (- (count x) 4))
to a JavaScript expression that looks like
x.substring(0, x.length - 4)
In other words, extremely efficient, possible via type analysis.accepting -4
which is unambiguous, would also be nice (but less likely to be approved)
well - it's not a breaking change, since until that is implemented any negative number would just be an error
@mfikes I know this was more in reference to using .length
for calling count
on strings but in that particular example you could also re-implement subs
to use String.prototype.slice
does slice share the data of the original mutable string ?
I do remember one of the string methods being significantly faster than another method that can do the equiavlent, though. I just can't remember whether that was substring vs slice or something else.. just that it surprised me to learn of it
@jesse.wertheim a simple patch to subs
could be considered—I suspect it would pan out if benchmarking works out and slice isn’t some newfangled thing only supported on recent VMs
hrm, MDN says initial definition dates back to ES3 spec so you should be good there, but yeah I'm curious about the benchmarking
It’s relatively easy to benchmark a proposed change across VMs—the capability is built into the compiler tree
incidentally I've been meaning to get the build set up on my machine so I can start dipping my toe into contributing
See the bottom of http://blog.fikesfarm.com/posts/2017-11-18-clojurescript-performance-measurement.html Maybe you are onto something
main downside is that it's technically a breaking change, but I hope nobody is doing (subs x init some-negative-number)
just to let it coerce to 0, lol
subs accepting a negative number was rejected by rich for clojure many years ago, so if it was added to clojurescript that would be yet another difference between clojure and clojurescript
lol, I was curious enough about why Rich rejected it to look it up and found a HN thread full of names I recognize
HN thread is rather punchy (shocker) so for the curious I'll link https://dev.clojure.org/jira/browse/CLJ-688 instead
People can get unpleasant when they disagree on technical topics (shocker)
Not that it is a good idea to get unpleasant about such things, of course. It does happen fairly often, though.
Evan Czaplicki in his talk "The Hard Parts of Open Source" proposes that perhaps having a discussion group that includes people who use a wide variety of programming languages exacerbates the issue: https://www.youtube.com/watch?v=o_4EX4dPppA
so, I'm timidly trying to move from lein to the new clj
cli tools, and I'm going through this page... there are some things I dont understand:
https://clojurescript.org/guides/quick-start
> Now that we have a simple program, let’s build and run some ClojureScript:
>`clj --main cljs.main --compile hello-world.core --repl`
where is cljs.main coming from? should that be on my classpath? when I run that command, I get a java.io.FileNotFoundException: Could not locate cljs/main__init.class or cljs/main.clj on classpath.
the clj
command works fine and loads a repl
cljs comes from the clojurescript library
Did you download the standalone ClojurScript JAR that was linked near the top of that page?
oh, sorry, perhaps that was Windows-specific, according to those instructions. Ignore me