Fork me on GitHub
#clojure-berlin
<
2015-07-30
>
socksy09:07:23

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.

akiel09:07:30

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

socksy09:07:00

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

socksy09:07:09

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

akiel09:07:02

what would you weite instead?

socksy09:07:14

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

akiel09:07:31

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

socksy10:07:01

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.

socksy10:07:00

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

hans10:07:12

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

socksy10:07:37

yes, but it’s not a prereq

hans10:07:40

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

socksy10:07:54

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

socksy10:07:24

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

hans10:07:42

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

hans10:07:49

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.

socksy10:07:22

you’re right. Makes sense

socksy10:07:57

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

hans10:07:54

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

socksy10:07:17

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

socksy10:07:19

good to know, cheers

nblumoe13:07:06

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

socksy13:07:58

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

socksy13:07:57

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

nblumoe13:07:33

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.

socksy13:07:15

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

nblumoe13:07:32

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"

socksy13:07:06

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

nblumoe13:07:08

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

socksy13:07:36

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

nblumoe14:07:45

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

nblumoe14:07:09

but nevertheless, I struggled more than once with other docstrings