Fork me on GitHub

@jpsoares106 4clojure is nice for doing various exercises but for some more curated exercises with, in turn, more curated solutions, I'd recommend


@jpsoares106 If you're interested in something more introductory, when I was first learning I started with 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)


Hi, I am new to clojure


I am using Lighttable, It's easy to me


But how can I interact with lein repl(2.8.1)


I have not used Lighttable before, so can't help you there. What kind of system are you using? (e.g. Windows, Mac, Linux?)


I'm using window


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 want to get input from keyboard such as (read)


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 [...])


Look at the higher order functions every, some, every-pred, and some-fn


They are very handy. Do you know why you can't apply and?


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)

Alex Miller (Clojure team)16:11:41

(every? identity [true false true]) is probably the best answer here

Lennart Buit19:11:42

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? ...)).

Lennart Buit19:11:24

(some ...) doesn’t completely cut it because it returns the first logical true item or nil

Lennart Buit19:11:13

maybe its me really wanting true/false instead of truthy/falsy

Alex Miller (Clojure team)19:11:35

you can use boolean instead of identity

Ben Grabow19:11:59

(some true? coll) sounds like what you're looking for, if you want to exclude truthy values that aren't true.

Alex Miller (Clojure team)19:11:07

(boolean (some boolean [false false]))

Alex Miller (Clojure team)19:11:27

if you are literally using booleans, then yes true? might be useful

Lennart Buit19:11:10

(every? identity [1 "abc" true]) is true, so then (boolean (some identity ...))

Lennart Buit19:11:56

would be the most faithful counterpart

Lennart Buit19:11:52

(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.

Lennart Buit07:11:20

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”.

Ben Grabow16:11:15

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

Alex Miller (Clojure team)16:11:48

in the core api, that’s usually referred to as a “logically true” value

Alex Miller (Clojure team)16:11:05

but I can’t say I have anything for you to read about it

Ben Grabow16:11:21

Tough to google for "logically true" haha

Ben Grabow16:11:36

I've come across the idea that fns ending in ? imply a boolean return. Is that the common practice in core code?

Ben Grabow16:11:09

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.

Alex Miller (Clojure team)16:11:28

these are often called “predicates” too

Ben Grabow16:11:33

*reference to the fact that the idea is discussed in "TJoC"

Alex Miller (Clojure team)16:11:00

you should pick up Joy of Clojure anyways :)

Ben Grabow16:11:06

A couple good reads I found: 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.

Lennart Buit20:11:33

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

Lennart Buit20:11:05

when, in haskell, a function returns Maybe a, I know damn well that it can fail

Lennart Buit20:11:19

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.


Thus all functions always would have the type Maybe


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.

Lennart Buit06:11:14

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.

Lennart Buit06:11:09

Also, in haskell, Maybe a is Functor/Applicative/Alternative/Monad so you get fail-fast for free

Lennart Buit06:11:41

Java interop is indeed still tricky, because well, you have no control over whether a function returns nil or throws an exception

Lennart Buit06:11:19

In my experience, when a nil travels through my code, it ends up crashing somewhere :’)

Lennart Buit06:11:08

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.


Or you get Nil, which you can think of similarly to Nothing

Lennart Buit06:11:40

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’.

Lennart Buit06:11:03

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)
    (/ x y)))
Those are the same

Lennart Buit07:11:29

Yeah sure. Cats has an either-type that you could return and make it a convesion to forbid methods returning nil

Lennart Buit07:11:39

but there is certainly no type checker to save you

Lennart Buit07:11:46

And then values are returned in Left or Right, so client code needs to treat it as such before it can do anything.

Lennart Buit07:11:52

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.

Lennart Buit07:11:48

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.


In the end you get the same behavior though


is there a more idiomatic way to do (str (apply str (drop-last 4 thread-url)) ….)?


how do you use subs to remove the last 4 chars?


user=> (def x "12345")
user=> (subs x 0 (- (count x) 4))


thats pretty nested too


i’ll try that tho thanks!


it doesn't unnecessarily allocate a seq and build a string


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


what does (subs x 0 (- (count x) 4)) compile to now in cljs?


count, in particular is a function call that involves a cond in its implementation


@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


unless there's a perf cost there in JS engines I'm unaware of


does slice share the data of the original mutable string ?


strings aren't mutable in JS (IIRC)


yep, strings themselves are immutable so no worries there


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


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


Ahh, I’ve always thought the arguments satisfy nat-int?. Hyrum…


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


Ahh, well ClojureScript follows Clojure


yeah that pretty much seals it


for some value of "follows"


oh well, easy enough to make your own


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 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.


Especially on HN ;-)


Well, any forum that big


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:

❤️ 4

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: > 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 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


It should be in specified in your deps.edn file


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


got it. im a dummy. I needed to cd into the top level directory 😅


deps.edn correctly doing its job


lol, when everything is new and scary again, you panic quickly


im so scared of approaching new tooling


Unexpected errors from new tools is confusing. No worries.

🙏 4