I just realised that ⎕LC is the line counter; I should have written ⎕LCL.
Louis > On 14 Aug 2016, at 01:37, Louis de Forcrand <[email protected]> wrote: > > And a third email about lambda locals. > > IMHO, a solution could be to introduce an extra assignment arrow which > denotes explicit > global assignment, and make the usual assignment arrow denote assignment > which is > local to lambdas (or have it the other way around). > If the standard doesn’t allow something like this, maybe something along the > lines of ⎕FX > like: > > ‘A’ ⎕LC data > ‘A’ ⎕GL data > > to denote explicit global or local assignment useful in lambdas or other > places, whichever > is not chosen to be denoted by the already existing arrow, could be used. > I would argue that the current arrow be used for local assignment, because > (aside from > personal taste) global assignment is more “dangerous” if inadvertently used. > As in, > a person who wants to just throw together a quick lambda doesn’t usually want > or need the effects of global assignment unless they can explicitly say so. > > Louis > >> On 13 Aug 2016, at 10:19, Juergen Sauermann <[email protected] >> <mailto:[email protected]>> wrote: >> >> Hi, >> >> the problem is that there is no syntactical means to "state otherwise". >> >> I personally find it convenient to assign to variables outside the lambda, >> for example >> to increment a counter on every iteration of the lambda. Of course one can >> criticize the way >> APL handles variables, but the limited number of function arguments and >> return values >> makes the scoping rules of APL almost inevitable. And I still believe that >> it is a bad thing >> if the scoping rules of lambdas are different from the scoping rules of >> "normal" defined functions. >> >> So the only room for changes that remains is to have a way of adding local >> variables to the header >> line of lambdas. Something along the lines of: >> >> FUN←'A B C' ⎕LOCALIZE { ... } >> >> where A B and C would become local variables in the named lambda FUN. >> >> I would also argue that lambdas are only a quick-and-dirty hack for >> specifying the function arguments >> of the EACH operator and friends; for serious functions ⎕FX and ∇ have all >> the features that are missing >> in GNU APL lambdas. >> >> /// Jürgen >> >> >> On 08/13/2016 02:11 PM, Elias Mårtenson wrote: >>> With regards to lack of local variables for lambda functions, I've observed >>> that local is the typical case, and nonlocal is somewhat rare. >>> >>> Wouldn't it make sense to make all variable assignments local for lambda >>> functions local, unless stated otherwise? >>> >>> Regards, >>> Elias >>> >>> >>> On 13 Aug 2016 8:05 pm, "Juergen Sauermann" <[email protected] >>> <mailto:[email protected]>> wrote: >>> Hi Louis, >>> >>> a quick answer to your question beforehand, I will look into the bugs later. >>> >>> GNU APL has implemented the power operator according to the description >>> in the book "Mastering Dyalog APL". The ISO standard says nothing about this >>> operator, it is simply not defined there. >>> >>> In "Mastering Dyalog APL" I haven't found the monadic case for the right >>> function argument >>> G of the power operator. In that book G seems to be always dyadic. So the >>> monadic case looks >>> like a new Dyalog invention. And, if it is defined like you say, IMHO not >>> the ultimate wisdom. >>> >>> What I do not like at all is the fact that in the dyadic case F is being >>> computed before G (it has to, >>> because you need the result ⍺F⍵ or F⍵ as left argument of G. And, as you >>> say, in the monadic >>> case F is being computed after G. >>> >>> I could imagine to implement the monadic G if it were always computed after >>> F so that the order >>> of execution is consistent for the monadic and dyadic cases. But if Dyalog >>> really has different orders >>> then I would prefer to not implement the monadic case in GNU APL at all >>> because then I would only >>> have the choice between an inconsistent execution order (which is, in my >>> opinion, bad) or an >>> incompatibility with Dyalog APL (which is also bad). >>> >>> Actually in GNU APL lambdas can be ambivalent, but monadic functions >>> (lambda or not) cannot be >>> ambivalent. Localizing variables assigned in lambdas automatically is >>> technically possible but would >>> break backward compatibility of existing workspaces. There was a >>> discussion on this topic earlier this >>> year, but no progress lately. I was thinking of some ⎕-function (like ⎕FX >>> but with {} syntax that would >>> allow you to created lambdas with more control over the localization of >>> variables). >>> >>> BTW, I read the word until in your description below as F being called >>> before G and not after G, >>> even in the monadic case. >>> >>> /// Jürgen >>> >>> >>> >>> On 08/13/2016 08:24 AM, Louis de Forcrand wrote: >>>> I’ll start with the question: >>>> >>>> The Dyalog 15.0 manual states that the power operator can take a >>>> function right argument. In this case, that function can be >>>> either monadic or dyadic, and can be a lambda. >>>> If it’s monadic: >>>> >>>> (F⍣G) ⍵ ←→ ⍵ ← F ⍵ until G ⍵ >>>> ⍺ (F⍣G) ⍵ ←→ ⍵ ← ⍺ F ⍵ until G ⍵ >>>> >>>> If it’s dyadic: >>>> >>>> (F⍣G) ⍵ ←→ ⍵ ← F ⍵ until ( F ⍵) G ⍵ >>>> ⍺ (F⍣G) ⍵ ←→ ⍵ ← ⍺ F ⍵ until (⍺ F ⍵) G ⍵ >>>> >>>> (Note that G is checked before the first time F is executed.) >>>> >>>> I don’t know what the ISO standard says on this, but in GNU APL, >>>> dyadic G works as in Dyalog. However, “monadic” lambda G has to >>>> be a weird function that takes both a left and a right argument, >>>> and discards the left one. That is: >>>> >>>> Dyalog: GNU: >>>> F⍣{G ⍵} F⍣{⍺⊢G ⍵} >>>> >>>> Is this because lambdas can’t be ambivalent? If so, I see two >>>> solutions: >>>> >>>> - Make ⍣ check G’s valence. >>>> >>>> - Better: I know it’s possible to write an ambivalent tradfn >>>> (function defined with the ∇-editor) by using ⎕NC on the >>>> left argument; wouldn’t it be possible to implement lambdas >>>> containing only ⍵ as ambivalent, so ⍺ is simply never used >>>> even if it is defined (or defined even if it isn’t used)? >>>> In fact, dyadic tradfns work in this way. >>>> >>>> Not only would this allow for cleaner use of ⍣, but it would >>>> also allow for “cleaner” case statements in lambdas: >>>> >>>> {⍎(‘case0’ ‘case1’ ‘case2’ ‘etc.’)[condition]} >>>> >>>> which is probably the only place one would use this. >>>> >>>> As of now, if ⍺ is present in one of the case statements but >>>> not in the rest of the function, then ⍺⊢ must be prepended to >>>> the lambda. >>>> >>>> While on the subject of lambdas, IMHO variables assigned inside >>>> lambdas should be made local. More than once I’ve used a named >>>> lambda in a tradfn and have found that one of its local variables >>>> was modified by the lambda. Although I imagine named lambdas must >>>> be a pain to implement. >>>> >>>> Also, I noticed that the assignment of a lambda to a name >>>> returns a vector of the name of the lambda. It would be >>>> interesting if it could return the actual lambda (of course this >>>> probably isn’t feasible, since it would require function >>>> returning expressions, a.k.a. tacit programming). >>>> >>>> >>>> Now on to the bugs: >>>> >>>> >>>> (g d)←'ATCTGAT' 'TGCATA' >>>> {((1↓X)Y((⊃X),Z)),[¯.5]X(1↓Y)((⊃Y),Z)⊣(X Y Z)←⍵}g d ⍬ >>>> TCTGAT ATCTGAT >>>> TGCATA GCATA >>>> ATCTGAT TGCATA >>>> {((1↓X)Y((⊃X),Z)),[.5]X(1↓Y)((⊃Y),Z)⊣(X Y Z)←⍵}g d ⍬ >>>> TCTGAT ATCTGAT >>>> TGCATA GCATA >>>> ATCTGAT TGCATA >>>> >>>> These should be transposed. ⎕IO ←→ 0, so ,[¯.5] should give a two row, >>>> three column matrix. >>>> >>>> >>>> ←——————— - - - ———————→ >>>> >>>> >>>> )SI >>>> ⋆⋆ >>>> >>>> ============================================================================== >>>> Assertion failed: idx < items_valid >>>> in Function: operator[] >>>> in file: ./Simple_string.hh:140 >>>> >>>> Call stack: >>>> >>>> ---------------------------------------- >>>> -- Stack trace at ./Simple_string.hh:140 >>>> ---------------------------------------- >>>> 0xa @@@@ >>>> 0xa @@@@ >>>> 0xa @@@@ >>>> 0xa @@@@ >>>> 0xa @@@@ >>>> 0xa @@@@ >>>> 0xa @@@@ >>>> 0xa @@@@ >>>> 0xa @@@@ >>>> ======================================== >>>> >>>> SI stack: >>>> >>>> Depth: 9 >>>> Exec: 0x7f98db4177b0 >>>> Safe exec: 0 >>>> Pmode: ⍎ (1↓R)((=/0⌷¨V)↓⍵⊃⍨~⍺)((2⊃⍵),1↑R←⍺⊃V) >>>> PC: 27 / >>>> Stat: (1↓R)((=/0⌷¨V)↓⍵⊃⍨~⍺)((2⊃⍵),1↑R←⍺⊃V) >>>> err_code: 0x50005 >>>> thrown: at Value.cc <http://value.cc/>:1051 >>>> e_msg_1: 'INDEX ERROR+' >>>> e_msg_2: ' (1↓R)((=/0⌷¨V)↓⍵⊃⍨∼⍺)((2⊃⍵),1↑R←⍺⊃V)' >>>> e_msg_3: ' ^ ^' >>>> >>>> Depth: 8 >>>> Exec: 0x7f98db41b9f0 >>>> Safe exec: 0 >>>> Pmode: ∇ >>>> ============================================================================== >>>> Assertion failed: idx < items_valid >>>> in Function: operator[] >>>> in file: ./Simple_string.hh:140 >>>> >>>> Call stack: >>>> *** do_Assert() called recursively *** >>>> ============================================================================== >>>> *** immediate_execution() caught other exception *** >>>> >>>> I’m sorry I couldn’t include the input preceding that )SI, it's long and >>>> very >>>> hard to reproduce. I hope this is enough to help :-⌈ >>>> >>>> ~———~ >>>> >>>> I’d like to thank you for your very hard work. I don’t know of any other >>>> APL >>>> which adheres to the standard while being as bug free as yours, and is a >>>> one-man project. Let alone all three! >>>> Keep in mind everything I suggest is the personal opinion of someone with >>>> very >>>> little experience with C++ish languages. I’m sure you know better than I >>>> do how >>>> to shape your APL. After all, you’re the one writing it! >>>> >>>> Best of luck, >>>> Louis >>>> >>> >> >
