bug-apl
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Bug-apl] Subtle parsing problem


From: Elias Mårtenson
Subject: Re: [Bug-apl] Subtle parsing problem
Date: Wed, 30 Jul 2014 22:05:58 +0800

OK, first of all, none of what follows are actually proposals or anything like that. They merely describe how I would have designed the language to make lambda functions behave more like they do in Lisp. It all comes down to having a concept that is referred to as "first class functions" in functional programming. The idea is that functions can be treated as any other type of value. They can be passed along to other functions, etc.

First, an assignment:

      foo ← {⍵+1} {⍵+2}

foo now contains an array containing two functions.

Let's look at what foo contains:

      foo
#<FN1> #<FN2>

Here, #<FNn> is used to represent a function. Note that Lambdas are scalar values.

      bar ← foo[1]

bar now contains the function {⍵+1}. Note that since functions are scalar values, bar would be seen in the output of )VARS and not )FNS.

Obviously, in this hypothetical variant of APL, you need a way to call a function that is a scalar value. This is similar to how you use FUNCALL or APPLY in Lisp to do this. Let's just re-use lamp for this:

      (⍎bar)10
11

In Lisp there is also a way to bind the "function slot" of a symbol to a lambda so that is behaves like a normal function.

Now, I can think of a few ways how proper first-class functions can be retrofitted in APL (involving some symbol that can be used to refer to a function as a first-class value. I.e. instead of using a symbol to force evaluation of a function, you'd do the opposite; have a symbol force the treatment of a function as a first-class value).

This is a discussion best reserved for another day though. :-)

Regards,
Elias


On 30 July 2014 21:43, Juergen Sauermann <address@hidden> wrote:
Hi Elias,

what you propose is i actually exactly what happens under the hood.
When you enter {⍵} 1 then {⍵} triggers the creation of a function λ1:

Z←λ1 ⍵
Z←⍵

and the original {⍵} 1 is being replaced by λ1 1.

The "problem" with niladic functions below is not at all related to lambdas but demanded
by the right to left evaluation in APL. Since niladic functions have no argument the are evaluated
as soon as the run-time parser sees them. Thats why your right lambda is evaluated before the SEL operator,
The reason why the left lambda is evaluated after the SEL is because the phrase containing it, i.e. {...} SEL B
is longer than the niladic lambda {...} alone.

The same would have happened if you had used defined functions or primitive functions instead of lambdas.

So your dream may have come true - except that it maybe turned out to be a nightmare?

/// Jürgen



On 07/29/2014 03:17 PM, Elias Mårtenson wrote:

I agree in part. My opinion is that all of these problems would be solvable if immediate lambdas required an explicit function call to be evaluated. I.e. {⍵} 1 should not evaluate to 1, but rather the function itself and the number one. Then, having a separate symbol to force evaluation.

Sadly, this is not the case, of course,so the above is just me dreaming. :-)

That said, I believe that lambdas should be extended to become more "functional" and generic. This includes lexical closures as well as proper first-class functions. To do so, however, would require first looking at how other APL's do it, as there is no reason to reinvent the wheel. Also, there are more important things to do first. :-)

Regards,
Elias

On 29 Jul 2014 20:48, "Juergen Sauermann" <address@hidden> wrote:
Hi,

I have put the power operator onto my long-term TODO list (aka README-4-compliance), SVN 402.

BTW the somewhat unexpected behavior of your niladic functions comes from the IMHO broken syntax
of the rank operator (which allows values where unaware people would expect functions). Before that
your right lambda would have returned a value and the SEL would have triggered a syntax error.

My concern in the context of lambdas is that if we drive that too far then we would create new cases
that nobody can understand anymore.

/// Jürgen


On 07/29/2014 02:11 PM, Elias Mårtenson wrote:
Hmm, so having a right-hand nildaic function passed to an operator simply doesn't work. Oh well, makes sense once you think about it. :-)

This was all part of experimentation I was playing around with while thinking about the power operator. Have you given that one any thought yet?

Regards,
Elias


On 29 July 2014 19:55, Juergen Sauermann <address@hidden> wrote:
Hi Elias,

this is because your lambdas are niladic. The right lambda is called before SEL,
while the left lambda is called by SEL. From SEL's perspective, 'then'; is a function
while 'else' is a value.

/// Jürgen



On 07/29/2014 07:21 AM, Elias Mårtenson wrote:
I was writing an operator that acts as an "if"-statement, calling one of two functions depending on the value of the argument:

∇Z ← (then SEL else) arg
  →(arg=1)/do¯then
  →(arg=0)/do¯else
  ⎕ES 'Illegal value for arg'
  →0
do¯then:
  Z ← then arg
  →0
do¯else:
  Z ← else arg


Note that the then and else functions are called with an argument "arg". When I call this operator with two nihilic lambda functions, I get very strange behaviour:

      ⊣ ({⎕←'was true'} SEL {⎕←'was false'}) 0
was false
      ⊣ ({⎕←'was true'} SEL {⎕←'was false'}) 1
was false
was true

I would expect to get an error message here, or perhaps seeing (⎕NC '⍵') to be 0. I certainly didn't expect to see both functions be called. My suspicion is that there is a problem with the parser somewhere, but I think Jürgen will have to look at this one.

Regards,
Elias






reply via email to

[Prev in Thread] Current Thread [Next in Thread]