Arc Forumnew | comments | leaders | submitlogin
2 points by tokipin 5884 days ago | link | parent

(fn name (...) ...) would be equivalent to the current (def name (...) ...), while (fn (...) ...) would be equivalent to the current (fn (...) ...). the intention isn't to replace the current form of fn, but to give it an optional parameter at the front so that both forms work

btw you can already use def in place of fn:

  arc>((def fun (x) (+ x 1)) 3)
  4
  arc>fun
  #<procedure: fun>
this version would be able to handle varargs, just not with the same notation as it currently uses. i mentioned (fn name ('() . args) ...) as a possibility, but i think something better would be

  (fn name ((v args)) ...)
sort of like the o notation for optional parameters. (fn name (() . args) ...) isn't that bad either. varargs of the form:

  (fn name (a1 . rest) ...)
would be unchanged. the only requirement necessary is that args always be in parens, and the only place where that currently conflicts is with full varargs


2 points by eds 5884 days ago | link

Even if your intention is to just add an optional parameter to 'fn, you still have to implement it in ac.scm. You can't even redefine it in Arc because it is dealt with specially in 'ac.

I still think there is a logical distinction between defining a function literal, and assigning that function to a variable. One should be implemented as an axiom, and the other really should be implemented in the core language. Pulling the latter into the former just doesn't make sense.

As for varargs notations, the only one I like is (fn ((v args)) ...). Because (fn args ...) is basically a case of destructuring, the (fn (() . args) just doesn't make sense. In fact that notation actually does work in the current Arc, it just throws away the first argument. (Which makes sense if you think through what that code is actually saying.)

But even considering the possible alternatives, I still think the current syntax is the most elegant.

-----

1 point by tokipin 5884 days ago | link

how about if i said: "make the name parameter of def be optional and rename it fn, and rename the current fn to axiomfn" ? we wouldn't be touching the axioms in that case except with a rename

i'm just saying there should be a functionality like that. how the internals are structured to meet that end isn't as significant so long as we're not butchering things. and i'm a big fan of the concise axiomatic approach. it's the reason i use Lua instead of Ruby. and that's why i think merging def and fn would be better -- because to the programmer it would be simpler, even though underneath it may need a bit more sophistication to handle the special case of full varargs

-----

3 points by eds 5884 days ago | link

There's still this logical distinction between creating an anonymous function and assigning it to a variable, and I don't think merging 'def and 'fn captures this distinction.

Note the differences in the use of 'def and 'fn. 'fn is used most frequently as a local function, while 'def is a global definition. If you provide a named form of 'fn that assigns a global name, then it will be really tempting to misuse that form in a local context where you really shouldn't be messing with global bindings.

And why should 'def get a pulled into 'fn but not 'afn or 'rfn? In some ways, those make much more sense than the integrated 'def form, but note that all of those were made explicitly different in the core language. We want to make it explicit how we are handling the naming (and scoping) of our functions. Thus the four or more different ways to define a function.

-----

1 point by tokipin 5883 days ago | link

> > There's still this logical distinction between creating an anonymous function and assigning it to a variable, and I don't think merging 'def and 'fn captures this distinction.

(fn name (arg) ...) and (fn (arg) ...) seem pretty distinct to me

> >Note the differences in the use of 'def and 'fn. 'fn is used most frequently as a local function, while 'def is a global definition. If you provide a named form of 'fn that assigns a global name, then it will be really tempting to misuse that form in a local context where you really shouldn't be messing with global bindings.

if fn is being used in a local context they probably won't need to give it a name

for afn and rfn i was actually thinking they could be merged as afn:

  (mac afm (first . rest)
       (if (alist first)
           `(afn ,first ,@rest)
           `(rfn ,first ,@rest)))
then there would only be two function-creating thingies: fn and afn. i stated elsewhere that i see the necessity for 'and' and 'aand'. fn and afn are substantially different in that the variable environments of their evaluated bodies are different, as well as producing different classes of functions

truthfully it would be nice if they could all be merged into one, and they could be, except for example 'self' would always be pre-set in lambdas which would be (conceptually) annoying. that would be tolerable though

Behold, the God Fn:

  (mac fn (first . rest)
       (if (alist first)
           `(afn ,first ,@rest)
           `(rfn ,first ,@rest)))

-----

2 points by eds 5883 days ago | link

> > There's still this logical distinction between creating an anonymous function and assigning it to a variable, and I don't think merging 'def and 'fn captures this distinction.

> (fn name (arg) ...) and (fn (arg) ...) seem pretty distinct to me

Think about the difference between (car x) and (scar x). Those are two distinct cases (assignment and retrieval), we wouldn't want to create a single 'car function that would do assignment if given an optional parameter.

  (_car x)   =>  (car x)
  (_car x y) =>  (scar x y)
Because these are two entirely different concepts. Similarly the assignment of a function to a variable is distinct from creating that function. In my opinion, merely creating an optional parameter for it in 'fn doesn't capture that distinction.

> if fn is being used in a local context they probably won't need to give it a name

Then why do 'afn and 'rfn exist?

> fn and afn are substantially different in that the variable environments of their evaluated bodies are different

And thus 'fn and 'def are different in that 'fn creates no binding and 'def creates a global binding.

-----

2 points by tokipin 5882 days ago | link

fn and def both create functions. in one case we donate money. in the other we donate money and get a star with our name on it. in both cases we've donated money. car vs scar would be like donating money vs robbing a bank

>> if fn is being used in a local context they probably won't need to give it a name

> Then why do 'afn and 'rfn exist?

to create self-referencing functions

> And thus 'fn and 'def are different in that 'fn creates no binding and 'def creates a global binding.

yes, and afn can create a different class of functions from fn. almkglor had a good point about requiring gymnastics in some cases with a God Fn. those sorts of issues wouldn't happen with (fn,def) -> fn and (afn,rfn) -> afn, except for the full vararg thing

if we use software structure/logic as the only metric, sure, they're all very different, but then we'll lose sight of the way the end user sees all these things

-----

2 points by eds 5882 days ago | link

> fn and def both create functions. in one case we donate money. in the other we donate money and get a star with our name on it.

No, the star gets permanently placed in the floor of the quad outside the central office. As opposed to 'afn and 'rfn where we get to keep the star.

Admittedly my 'car and 'scar example wasn't accurate. Let me try again. Say we have a version of 'table called 'ntable that is just like table except it assigns the new table to a global variable. Now suppose we redefine 'table to take an optional parameter, in which case it acts like 'ntable. But all this does is confuse the purpose of 'table, which is to create a table, and 'ntable which creates a table in the global namespace. The overloading here doesn't help shorten or clarify code. So we remove one function from the global namespace. So what?

Unlike in real life, the presence or absence of the star really does matter here, enough that the two shouldn't be condensed into a single operation.

>>> if fn is being used in a local context they probably won't need to give it a name

>> Then why do 'afn and 'rfn exist?

> to create self-referencing functions

Exactly! So you can use the function in more places than just the return value. 'def is similar in that the name allows it to be referenced elsewhere (or inside the definition), and this is totally different from the one-shot usage that 'fn gets most of the time.

> if we use software structure/logic as the only metric, sure, they're all very different, but then we'll lose sight of the way the end user sees all these things

I think we are making very different assumptions about the way the user thinks about 'fn and 'def. When I see 'fn, I think local/anonymous function. When I see 'def on the other hand, I think global/named function (and yes, where the name goes is an important issue, even to an end user). I don't think it is a simplification of this model to merge the two operations.

-----

1 point by tokipin 5882 days ago | link

when i see fn, i see "fundamental function-creating function." i see def as "(= name (fundamental function-creating function))." i said elsewhere that i can see how someone familiar with lisp would see fn and def as essentially lambda and set, and

  (lambda name (arg) ...)
would definitely be odd. but the name isn't "lambda," it's "fn." and i conceive that as "function," which has no semantic bias to locality or scope

-----

1 point by almkglor 5882 days ago | link

ooh, ECMAscript:

  function foo(x){
    return function(){return x;}
  }

-----

1 point by almkglor 5883 days ago | link

Please realize that this makes the following otherwise OK code much more difficult to express using your "God Fn":

  ((afn (m-tree)
    (when (in-sight m-tree)
      (map
        (fn (node)
          (render node)
          (self node))
        m-tree!children)))
    m-tree)
So no. I don't think this puritan attempt at merging ideas is a good one.

"All processes are impermanent ... All processes are afflicted ... All phenomena are not ‘Self’; when this is seen with knowledge, one is freed from the illusion of affliction. This is the pathway to purity."

-----

1 point by tokipin 5883 days ago | link

uh... it would just be a replacement of 'afn' with 'fn', unless i'm missing something [edit]ah, i see the extra fn you lodged in there

what about:

  ((afn (m-tree)
    (when (in-sight m-tree)
      (map
        (afn (node)
          (self node)
          (self node))
        m-tree!children)))
    m-tree)
i wonder how we would refer to the different selves within the inner function without explicitly setting something in the outer one or using rfn. a let around the inner function isn't that bad. in any case, good catch

-----