• Why don't lambda functions work inside defined functions?

    From Brian McGuinness@21:1/5 to All on Sun Jun 5 13:08:48 2022
    I have been experimenting with simple lambda functions to see how they work. But I ran into behavior that I don't understand, and I haven't found good documentation to explain what is going on.

    This works as expected:

    ({⍵,+/¯2↑⍵}⍣10) 0 1
    0 1 1 2 3 5 8 13 21 34 55 89

    But this doesn't work:


    [0] A←FIBONACCI N
    [1] A←({⍵,+/¯2↑⍵}⍣N-2) 0 1


    FIBONACCI 12
    ¯2 ¯2 ¯4 ¯6 ¯10 ¯16 ¯26 ¯42 ¯68 ¯110 ¯178 ¯288 ¯466 0 1

    If I tried to do this using only normal defined functions I would have to use two separate functions, so it seems to me that using a lambda function should be a cleaner way to perform the operation. But I don't see how to make this work.

    --- Brian McGuinness

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Rav@21:1/5 to Brian McGuinness on Sun Jun 5 18:11:06 2022
    On 6/5/2022 4:08 PM, Brian McGuinness wrote:
    I have been experimenting with simple lambda functions to see how they work. But I ran into behavior that I don't understand, and I haven't found good documentation to explain what is going on.

    This works as expected:

    ({⍵,+/¯2↑⍵}⍣10) 0 1
    0 1 1 2 3 5 8 13 21 34 55 89

    But this doesn't work:


    [0] A←FIBONACCI N
    [1] A←({⍵,+/¯2↑⍵}⍣N-2) 0 1


    FIBONACCI 12
    ¯2 ¯2 ¯4 ¯6 ¯10 ¯16 ¯26 ¯42 ¯68 ¯110 ¯178 ¯288 ¯466 0 1

    If I tried to do this using only normal defined functions I would have to use two separate functions, so it seems to me that using a lambda function should be a cleaner way to perform the operation. But I don't see how to make this work.

    --- Brian McGuinness

    If I understand correctly, it doesn't look to me like doing the same
    thing with a defined function is doing anything differently. In
    immediate execution mode:

    ({⍵,+/¯2↑⍵}⍣12-2) 0 1
    ¯2 ¯2 ¯4 ¯6 ¯10 ¯16 ¯26 ¯42 ¯68 ¯110 ¯178 ¯288 ¯466 0 1

    But:

    ({⍵,+/¯2↑⍵}⍣(12-2)) 0 1
    0 1 1 2 3 5 8 13 21 34 55 89

    I'm not familiar with the power function, but perhaps it's a precedence
    issue, which the parentheses solves. So change your defined function to:


    [0] A←FIBONACCI N
    [1] A←({⍵,+/¯2↑⍵}⍣(N-2)) 0 1


    / Rav

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Charles Brenner@21:1/5 to Rav on Mon Jun 6 13:03:13 2022
    On Sunday, June 5, 2022 at 3:11:09 PM UTC-7, Rav wrote:
    On 6/5/2022 4:08 PM, Brian McGuinness wrote:
    I have been experimenting with simple lambda functions to see how they work. But I ran into behavior that I don't understand, and I haven't found good documentation to explain what is going on.

    This works as expected:

    ({⍵,+/¯2↑⍵}⍣10) 0 1
    0 1 1 2 3 5 8 13 21 34 55 89

    But this doesn't work:


    [0] A←FIBONACCI N
    [1] A←({⍵,+/¯2↑⍵}⍣N-2) 0 1


    FIBONACCI 12
    ¯2 ¯2 ¯4 ¯6 ¯10 ¯16 ¯26 ¯42 ¯68 ¯110 ¯178 ¯288 ¯466 0 1

    If I tried to do this using only normal defined functions I would have to use two separate functions, so it seems to me that using a lambda function should be a cleaner way to perform the operation. But I don't see how to make this work.

    --- Brian McGuinness
    If I understand correctly, it doesn't look to me like doing the same
    thing with a defined function is doing anything differently. In
    immediate execution mode:

    ({⍵,+/¯2↑⍵}⍣12-2) 0 1
    ¯2 ¯2 ¯4 ¯6 ¯10 ¯16 ¯26 ¯42 ¯68 ¯110 ¯178 ¯288 ¯466 0 1
    But:

    ({⍵,+/¯2↑⍵}⍣(12-2)) 0 1
    0 1 1 2 3 5 8 13 21 34 55 89
    I'm not familiar with the power function, but perhaps it's a precedence issue, which the parentheses solves. So change your defined function to:


    [0] A←FIBONACCI N
    [1] A←({⍵,+/¯2↑⍵}⍣(N-2)) 0 1


    / Rav
    Nice work. That solves the puzzle except for a small point of language. ⍣ is an operator hence, contrary to the rule for a function, it has short right scope - i.e. "12" or "(12-2)" - (and long left scope).

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bob Smith@21:1/5 to Charles Brenner on Tue Jun 7 10:50:30 2022
    On 6/6/2022 4:03 PM, Charles Brenner wrote:
    On Sunday, June 5, 2022 at 3:11:09 PM UTC-7, Rav wrote:
    On 6/5/2022 4:08 PM, Brian McGuinness wrote:
    I have been experimenting with simple lambda functions to see how they work. But I ran into behavior that I don't understand, and I haven't found good documentation to explain what is going on.

    This works as expected:

    ({⍵,+/¯2↑⍵}⍣10) 0 1
    0 1 1 2 3 5 8 13 21 34 55 89

    But this doesn't work:


    [0] A←FIBONACCI N
    [1] A←({⍵,+/¯2↑⍵}⍣N-2) 0 1


    FIBONACCI 12
    ¯2 ¯2 ¯4 ¯6 ¯10 ¯16 ¯26 ¯42 ¯68 ¯110 ¯178 ¯288 ¯466 0 1

    If I tried to do this using only normal defined functions I would have to use two separate functions, so it seems to me that using a lambda function should be a cleaner way to perform the operation. But I don't see how to make this work.

    --- Brian McGuinness
    If I understand correctly, it doesn't look to me like doing the same
    thing with a defined function is doing anything differently. In
    immediate execution mode:

    ({⍵,+/¯2↑⍵}⍣12-2) 0 1
    ¯2 ¯2 ¯4 ¯6 ¯10 ¯16 ¯26 ¯42 ¯68 ¯110 ¯178 ¯288 ¯466 0 1
    But:

    ({⍵,+/¯2↑⍵}⍣(12-2)) 0 1
    0 1 1 2 3 5 8 13 21 34 55 89
    I'm not familiar with the power function, but perhaps it's a precedence
    issue, which the parentheses solves. So change your defined function to:


    [0] A←FIBONACCI N
    [1] A←({⍵,+/¯2↑⍵}⍣(N-2)) 0 1


    / Rav
    Nice work. That solves the puzzle except for a small point of language. ⍣ is an operator hence, contrary to the rule for a function, it has short right scope - i.e. "12" or "(12-2)" - (and long left scope).

    Charles is exactly right. Moreover, there is one difference in the way
    dyadic operators work in APL2 and NARS2000 versus Dyalog with numeric
    strand right operands. While they all implement short right scope, in
    APL2 and NARS2000

    f⍣1 2 3 ←→ (f⍣1) 2 3

    whereas in Dyalog

    f⍣1 2 3 ←→ f⍣(1 2 3)

    One way to look at the difference is in the interpretation of 1 2 3 as
    three tokens or a single token.

    --
    _________________________________________
    Bob Smith -- bsmith@sudleydeplacespam.com
    http://www.sudleyplace.com - http://www.nars2000.org

    To reply to me directly, delete "despam".

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Charles Brenner@21:1/5 to Bob Smith on Tue Jun 7 11:44:33 2022
    On Tuesday, June 7, 2022 at 7:50:35 AM UTC-7, Bob Smith wrote:
    On 6/6/2022 4:03 PM, Charles Brenner wrote:
    On Sunday, June 5, 2022 at 3:11:09 PM UTC-7, Rav wrote:
    On 6/5/2022 4:08 PM, Brian McGuinness wrote:
    I have been experimenting with simple lambda functions to see how they work. But I ran into behavior that I don't understand, and I haven't found good documentation to explain what is going on.

    This works as expected:

    ({,+/¯2↑}10) 0 1
    0 1 1 2 3 5 8 13 21 34 55 89

    But this doesn't work:


    [0] A←FIBONACCI N
    [1] A←({,+/¯2↑}N-2) 0 1


    FIBONACCI 12
    ¯2 ¯2 ¯4 ¯6 ¯10 ¯16 ¯26 ¯42 ¯68 ¯110 ¯178 ¯288 ¯466 0 1

    If I tried to do this using only normal defined functions I would have to use two separate functions, so it seems to me that using a lambda function should be a cleaner way to perform the operation. But I don't see how to make this work.

    --- Brian McGuinness
    If I understand correctly, it doesn't look to me like doing the same
    thing with a defined function is doing anything differently. In
    immediate execution mode:

    ({,+/¯2↑}12-2) 0 1
    ¯2 ¯2 ¯4 ¯6 ¯10 ¯16 ¯26 ¯42 ¯68 ¯110 ¯178 ¯288 ¯466 0 1
    But:

    ({,+/¯2↑}(12-2)) 0 1
    0 1 1 2 3 5 8 13 21 34 55 89
    I'm not familiar with the power function, but perhaps it's a precedence >> issue, which the parentheses solves. So change your defined function to: >>

    [0] A←FIBONACCI N
    [1] A←({,+/¯2↑}(N-2)) 0 1


    / Rav
    Nice work. That solves the puzzle except for a small point of language. is an operator hence, contrary to the rule for a function, it has short right scope - i.e. "12" or "(12-2)" - (and long left scope).
    Charles is exactly right. Moreover, there is one difference in the way dyadic operators work in APL2 and NARS2000 versus Dyalog with numeric
    strand right operands. While they all implement short right scope, in
    APL2 and NARS2000

    f1 2 3 ←→ (f1) 2 3

    whereas in Dyalog

    f1 2 3 ←→ f(1 2 3)

    Thanks Bob. That's good to know and I didn't.
    Another situation where Morton chose to abandon APL2's parenthesis requirement is multiple assignment:
    In APL2: (one another)←1 'ther'
    Dyalog permits: one another←1 'ther'
    Morton expressed remorse for this, and eventually I saw why. I often invoke the display utility function #.disp, i.e. disp (3 2'a' 23 ('b' 'cd')). Sometimes when my program crashed while inside namespace #.ns, I would thoughtlessly write disp x←
    Function 7, which usually works fine. But if Function returns a 2-element vector, uh oh!
    So I began writing (xyz abc)← ..., and having thus violated my life-long habit of always omitting unnecessary punctuation in my APL code, the floodgates are getting shakey. Occasionally I now add extra parentheses for symmetry or a superfluous monadic
    for clarity.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bob Smith@21:1/5 to Charles Brenner on Tue Jun 7 18:06:28 2022
    On 6/7/2022 2:44 PM, Charles Brenner wrote:
    [..]
    Thanks Bob. That's good to know and I didn't.
    Another situation where Morton chose to abandon APL2's parenthesis requirement is multiple assignment:
    In APL2: (one another)←1 'ther'
    Dyalog permits: one another←1 'ther'
    Morton expressed remorse for this, and eventually I saw why. I often invoke the display utility function #.disp, i.e. disp (3 2'a' 23 ('b' 'cd')). Sometimes when my program crashed while inside namespace #.ns, I would thoughtlessly write disp x
    Function 7, which usually works fine. But if Function returns a 2-element vector, uh oh!
    So I began writing (xyz abc)← ..., and having thus violated my life-long habit of always omitting unnecessary punctuation in my APL code, the floodgates are getting shakey. Occasionally I now add extra parentheses for symmetry or a superfluous
    monadic ⊆ for clarity.

    Yes, I agree completely with the need for surrounding parens in
    selective specifications. Principally, I want it for ease of parsing
    the line visually. Fortunately for you, Dyalog APL disallows the
    re-assignment of a variable to the name of an existing function, so disp
    won't be changed.

    Parens are already required in some instances of SelSpec, such as distinguishing between

    1 1a ←b and
    (1 1a)←b

    which says to me that they should be required in every case of SelSpec.

    Also, in Dyalog APL you might be required to insert parens in an unusual
    place: around the *rightmost* part of a statement, such as

    a←1 ⋄ a b←'ab' ⋄ a b
    ab
    a←1 ⋄ a (b←'ab')
    1 ab

    --
    _________________________________________
    Bob Smith -- bsmith@sudleydeplacespam.com
    http://www.sudleyplace.com - http://www.nars2000.org

    To reply to me directly, delete "despam".

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Brian McGuinness@21:1/5 to All on Tue Jun 7 15:53:47 2022
    Thanks, now I see what's going on.

    --- Brian McGuinness

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)