Fork me on GitHub

Takes a vector of function specs and a body, and generates a set of
  bindings of functions to their names. All of the names are available
  in all of the definitions of the functions, as well as the body.”
It seems that the official clojure documentation makes a lot of sense to those that already know what a function does.


@socksy: is that letfn? i'm just guessing.


had to look for an example, then the explanation made perfect sense


but really, this is not a good way of writing documentation


what would you weite instead?


(and i think i’m now against letfn for 95% of the time, and shall be eradicating its usage throughout our codebase)


i also don't really use it - every time i do, i end up with a normal let or even just put functions in vars


I’m not sure how I’d write it. Something like “ A form of let binding specifically for creating functions in the let scope. Inside of the binding vector you have [(fn-name [args] (body))], which you can then call as (fn-name) inside of the binding as (fn-name args). Each fn in the binding vector can access each other.” But really, good documentation requires a lot of thought, and that probably can be improved a lot. Also depends on the let documentation.


but yeah, the reason i’m against it in our code base is that it’s been used as a top level construct, with only one function binding. Totally unnecessary and harder to read than just an extra private function


i think the term "recursive" would clarify things a bit. letfn is useful for (mutually) recursive local functions, no?


yes, but it’s not a prereq


not a prereq, but why would you use letfn if you don't need the recursive aspect of it?


(but to me it seems like one of the only acceptable use cases)


i mean, it’s not actually recursive, it just lets you refer to any other function inside of the let binding, hence letting you do mutually recursive things


it is also the only way to define a recursive local function.


so i take letfn as an indicator for upcoming recursion, and let is clearly defining only non-recursive functions. the documentation would do no harm pointing out that letfn is only needed for recursive local functions.


you’re right. Makes sense


never occurred to me that clojure’s one pass “can’t refer to symbols not yet defined in this file” also stops you from doing mutually recursive functions. Kinda shitty


It does not really stop you. If you need mutually recursive global functions, use declare.


tbf, the web page documentation for letfn has a mutually recursive fn as its example. It’s just the doc-string I’m taking exception at


good to know, cheers


tbh I think the docstring is quite clear in explaining what letfn does. It does not cover why you would want to use it, for which use cases. But this seems to apply to almost all docstrings, doesn't it? And that is probably a good idea, to avoid bloating the docstrings and quite abstract functions are hard to describe with respect to their use cases. @socksy


My issue is that it’s only clear when you already know what it does


which you can argue as the reason for the doc string, just to check which arguments it has, but really the function signature should be clear enough in that respect


hm, I dare to disagree. The name alone explains a lot - assuming one knows let already - and then the only missing piece is, that the functions are available not only in the body (or consecutive functions) but in ALL of the functions.


I know what a let binding is, I know what functions are, and yet from that docstring i couldn’t work out what letfn did from the docstring, which is possibly a testament to my stupidity, but this really isn’t an abstract function


When I read the docstring - first time a few minutes ago - I could rather easily understand what it does. However, without reading the follow up discussion I did not think "Hey, awesome, I am going to use that for mutually recursive, local functions"


and you missed a subtlety I think. It’s not like a let fn, since the binding vector is perfectly allowed to have an odd number of forms


uh, indeed, I wasn't aware of that. and cannot get it from the docstring alone. need to investigate a bit more! simple_smile


(letfn [(foo [args] (print args))] (foo bar))


ah right. well I am now thinking about the syntax of the letfn special form, specifically the functions specs. That's a bit unfortunate I would say. But as every function spec has enclosing parenthesis, it's of course quite obvious, that there can be odd number of bindings


but nevertheless, I struggled more than once with other docstrings