clojure-berlin

where Berlin peeps hang out
socksy 2015-07-30T09:44:23.000058Z

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.

2015-07-30T09:54:30.000059Z

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

socksy 2015-07-30T09:54:36.000060Z

yep

socksy 2015-07-30T09:55:00.000061Z

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

socksy 2015-07-30T09:55:09.000062Z

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

2015-07-30T09:56:02.000063Z

what would you weite instead?

socksy 2015-07-30T09:56:14.000064Z

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

2015-07-30T09:57:31.000065Z

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

socksy 2015-07-30T10:04:01.000066Z

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.

socksy 2015-07-30T10:15:00.000067Z

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

hans 2015-07-30T10:15:12.000068Z

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

socksy 2015-07-30T10:15:37.000069Z

yes, but it’s not a prereq

hans 2015-07-30T10:16:40.000070Z

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

socksy 2015-07-30T10:16:54.000071Z

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

socksy 2015-07-30T10:17:24.000072Z

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

hans 2015-07-30T10:17:42.000073Z

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

hans 2015-07-30T10:18:49.000074Z

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.

socksy 2015-07-30T10:20:22.000076Z

you’re right. Makes sense

socksy 2015-07-30T10:21:57.000077Z

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

hans 2015-07-30T10:23:54.000078Z

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

socksy 2015-07-30T10:24:17.000079Z

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

socksy 2015-07-30T10:25:19.000080Z

good to know, cheers

nblumoe 2015-07-30T13:53:06.000081Z

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

socksy 2015-07-30T13:53:58.000082Z

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

socksy 2015-07-30T13:54:57.000083Z

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

nblumoe 2015-07-30T13:56:33.000084Z

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.

socksy 2015-07-30T13:57:15.000085Z

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

nblumoe 2015-07-30T13:57:32.000086Z

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"

socksy 2015-07-30T13:58:06.000087Z

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

nblumoe 2015-07-30T13:59:08.000088Z

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

socksy 2015-07-30T13:59:36.000089Z

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

nblumoe 2015-07-30T14:06:45.000092Z

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

nblumoe 2015-07-30T14:19:09.000093Z

but nevertheless, I struggled more than once with other docstrings