> Begin forwarded message:
>
> From: Louis de Forcrand <[email protected]>
> Subject: Re: [Bug-apl] A couple of bugs, and a question on the power operator
> Date: 13 Aug 2016 21:17:39 GMT-4
> To: "[email protected]" <[email protected]>
>
> Ok, so the power operator for dyadic G (and either monadic or dyadic F)
> could be modelled like this:
>
> ∇
> [0] Z←X(F PD G)Y;E
> [1] E←(0=⎕NC'X')↓'X F Y'
> [2] Z←⍎E
> [3] L:→0⍴⍨Z G Y
> [4] Z←⍎E,'←Z' ◊ →L
> ∇
>
> This looks fine and dandy for things like:
>
> {⍵*2}PD{⍺≥10×⍵}⊢2
> 256
> {⍵*2}⍣{⍺≥10×⍵}⊢2
> 256
>
> But I agree with you that it shouldn’t be set up like this:
>
> {⍵*2}PD{⍺<10×⍵}⊢2
> 4
> {⍵*2}⍣{⍺<10×⍵}⊢2
> 4
>
> IMHO that should return the first value for which G is true, which in this
> case is two and not four. But yes, this is the way Dyalog does it.
>
> And about the “until”, I probably should have said that as “while not G”.
>
> Louis
>
>
>
>> On 13 Aug 2016, at 08:05, 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
>>>
>>
>