Conversation started Mar 21, 2018 at 18:30.
Mar 21, 2018 6:30 PM
Welcome to the APL Cultivation!
So, we've covered all the building blocks you'll use to build your APL program.
Now we have to figure out how to actually write some APL programs.
When I start on a new project, the first thing I have to decide is how this code should be used.
It could be a small monolithic application. For that I'd use a single tradfn.
It could be a collection of small computation tools. For that I'd make a namespace of tacit functions and one-liner dfns.
Of course, it could be a large application too. Then a collection of classes might be in place.
Other than a bootstrapping program, I'd strive to keep things rather functional. Everything (tradfns too) should take at least one argument and return a result, and should not use global variables.
@Adám that should be implied...
> should not use global variables
@EriktheOutgolfer You'd be surprised what people write… A bunch of non-result, niladic tradfns.
I'd like to know how can I initialize a separate workspace to work in a specific project. Up until now, I've only ever started the REPL environment to try and solve challenges, but how can I actually begin a project? When I save a workspace, does it save as a workspace file? Does each class have its own file?
@J.Sallé OK, let's address that.
@Adám that's the worst sin one can ever commit while programming! not sure as to if they ever managed to write code which adds two numbers
Mar 21, 2018 6:37 PM
Actually, these days, I'd recommend developing in a CLEAR WS (what you get when you just start APL).
@J.Sallé I'd write )ed ○myclass and populate the skeleton the editor provides.
You all take "not using global variables" for granted, but if the application is a model of something based on a bunch of matrices containing parameter tables, historical data and assumptions, treating a collection of matrices as an "in memory database" is quite a rational thing to do. Excel wouldn't be a very nice tool if you couldn't refer to all the cells, but had to write code that passed things as arguments :-)
Then I'd type ]save myclass /path/ which would create a myclass.dyalog file.
Every time I would close the editor after editing myclass, the changes would automatically be written back to file.
Also, performance. It's faster to change state a lot of the time. The analogy I've heard is that it's easier to move a pebble an inch than to create a new universe where the pebble is moved over an inch.
@Adám so you only need to do ]save once?
(you'd still want to write as much code in a functional style as you possibly can)
Mar 21, 2018 6:41 PM
@MortenKromberg just because we use Excel as a programming language here at PPCG doesn't mean it's actually intended to be a programming language :P it's a tool for spreadsheet presentation, and it actually does a good job with copy-pasting
@J.Sallé Yes. Then the editor will make sure to save all changes. But note: only the editor. assignments and ⎕FX and ⎕FIX will not update the files.
@Adám okay, I get it.
Btw, for purely functional tasks, I'd go with a dfn.
And the dfns are saved to the workspace, right? How do I save that?
In general, I like being able to see all my code at once, so I'll use a scripted namespace to keep my code in.
@J.Sallé Don't worry about the workspace. You can do ]save mydfn /path/ too.
Mar 21, 2018 6:45 PM
ah, okay
@Adám what would you do for a task that even though requires only one function requires the function to be very complex?
wouldn't a dfn grow towards infinity?
So I'd begin with )ed ⍟myproject which creates a template for the scripted namespace. Then I'd do ]save myproject /path/, and subsequent edits to the script will be auto-saved.
@EriktheOutgolfer That is very rarely needed in APL. I'd split well-defined parts of the code (i.e. parts that take some variables as arguments and returns a usable result without the intermediary values being needed other places) into sub-functions.
Of course, each programmer has his style, but I like having my functions fit on screen.
@Adám unfortunately, with finite space you can only represent so many functions at once :)
And I'd group functions into collections (i.e. namespaces) based on their category.
@EriktheOutgolfer But each carefully named sub-function can fit on a screen.
@Adám oh like the webpage of dfns (not actual dfns) presents?
Mar 21, 2018 6:49 PM
@EriktheOutgolfer Yes.
@Adám could you give a simple example of what that namespace would look like?
@J.Sallé Sure. Give me a min to find a good example.
Thanks :D
Not sure if this is useful but I'm working on a project where existing Python code is being converted into APL. There is an apl and a python sub-folder below github.com/romilly/breadboarder/tree/master/src. The APL is only partially complete, we're halfway through the conversion exercise.
Mar 21, 2018 6:54 PM
So I have a class which says :Include #.MS3SiteUtils and that includes all the functions from the utility namespace into the class.
I didn't want to have to "dot" into sub-namespaces, but there were too many utility functions to just bunch them all together. Therefore, I used :Section to split the namespace. This allowed me to use the editor's tree-view to navigate.
@Adám and I assume you can import a specific section?
You'll notice that most functions fit on about page. I use plenty of whitespace and every function needs at least a comment saying what it does.
@J.Sallé No. Sections are only for the human.
@Adám sections D, E and F look pretty longer than that to me (1366x768)
@EriktheOutgolfer Sections are not functions.
In case anyone is interested: To load the APL code, after a git checkout, I would type
]load C:\Devt\breadboarder\src\apl\*
In versions <17.0 which is as yet unreleased, you will need to do that twice because a few of the source files will fail to load due to missing base classes. The second time, the base classses are define (in v17.0 we allow classes to be fixed even if dependencies are missing).
Mar 21, 2018 7:00 PM
@EriktheOutgolfer The longest function in section D is 12 lines.
@Adám I mean between :SECTION and :ENDSECTION, not functions
@Adám oh, okay.
oh wait you said functions
To exercise it, call TestDrawBreadBoard, which creates the same svg that the python test case has previously created and compares it.
@EriktheOutgolfer Sure. As you said, sometimes we need a lot of code. So break the code into tiny bits.
Mar 21, 2018 7:04 PM
Damn, I gotta go now, my boss just called a meeting. I'll catch up when I'm done there. Thanks for the tips guys, I'll be sure to use them :D
I tend to reserve an area (a section or namespace) for small general purpose utilities, like string splitting (≠⊆⊢) and maybe "if" ({⍺←⊢ ⋄ ⍺⍺⍣(⍵⍵ ⍵)⊢⍵}).
For now, let's not worry about golfing.
Sure
Clearly, this is a "utility" function. So I'd go with a single tradfn or dfn.
@Adám you won't believe how hard I discourage spoiling yourself over Jelly HyperTraining...
@EriktheOutgolfer Spoiling myself?
Mar 21, 2018 7:09 PM
@Adám who knows who has posted an APL answer over there...
@EriktheOutgolfer Nobody has.
So I'd begin a new function )ed Scramble and probably begin it as a tradfn. We can always convert it to a dfn or tacit fn later.
Obviously we're looking for specific patterns (word), but preferring APL over regex, I'd want to minimise the regex usage.
So I'll outline my function like this:
text←Scramble text

text←'\pL+' ⎕R something ⊢ text
The regex part just finds the words, and then we need to find "something" that can process each word as needed (we'll define that on the empty line).
@Adám what does '\pL+' match?
@H.PWiz That's Perl regex for one or more characters of the Letter class.
Okay. I'm used to '\w+'
@H.PWiz Yeah, but that'll match abd234 too.
Mar 21, 2018 7:15 PM
So what are we doing with strings like abcd234?
rearranging the letter bit, or leaving it?
@H.PWiz Scramble the abcd part.
Then I'll define a dfn that just expects a single word as its argument.
We know that we do not move the first and last letters, so lets begin by removing those:
something←{
middle←1↓¯1↓⍵.Match
⍵.Match is just the matched text as the argument to ⎕R's operand is a namespace.
Now we need to classify the characters into the four groups.
So we need to a membership between each letter and the groups. One way we can do that is with an outer product:
⎕←'hi ppcg'∘.∊'bdfhkl' 'acemnorsuvwxz' 'gpqy' 'it'
@Adám
1 0 0 0
0 0 0 1
0 0 0 0
0 0 1 0
0 0 1 0
0 1 0 0
0 0 1 0
@Adám lol my OCD shouts "DO ⍸¨↓ DAMMIT"
@EriktheOutgolfer Nope, let's do real multi-dimensional arrays.
So on each row, we need to find the index of the one.
@Adám I know, that's why I don't listen to my OCD
Mar 21, 2018 7:27 PM
So we need the "find-first-one" function. For such a simple thing, I'd go tacit:
⎕←0 0 1 0⍳1 ⋄ ⎕←(⍳∘1)0 0 1 0
@Adám
3
3
And on each row is ⍤1 (on each array of rank 1, i.e. vector, i.e. row):
⍞←⍳∘1⍤1⊢'hippcg'∘.∊'bdfhkl' 'acemnorsuvwxz' 'gpqy' 'it'
@Adám 1 4 3 3 2 3
Now we have:
text←Scramble text
something←{
middle←1↓¯1↓⍵.Match
FirstOne←⍳∘1
Rowwise←⍤1
Classify←∘.∊∘'bdfhkl' 'acemnorsuvwxz' 'gpqy' 'it'
FirstOne Rowwise Classify middle

text←'\pL+' ⎕R something ⊢ text
@Adám missing a }?
Mar 21, 2018 7:33 PM
@H.PWiz We're just programming, this isn't runnable at all yet.
Oh, my bad
tbf it does look like somebody pressed Shift+Enter instead of Shift+] though...keys next to each other
@EriktheOutgolfer Oh, right :-D
We can use a construct like @(⍵=type)⊢text}¨type to process each type and do something to the collection of characters that have that type.
What we need to do is to shuffle. So I'd make a small utility function that shuffles its argument.
@Adám what is type
@Adám Using ?⍨ I presume
Mar 21, 2018 7:37 PM
@EriktheOutgolfer the class it belongs in of 'bdfhkl' 'acemnorsuvwxz' 'gpqy' 'it'. Sorry for inconsistent terminology.
@H.PWiz Yes:
⍞←{⍵[?⍨≢⍵]}'abcdef'
@Adám dcbafe
So I'd define that as Shuffle←{⍵[?⍨≢⍵]}.
I think {text⊢←Shuffle@(⍸⍵=type)⊢text}¨type will work.
@Adám What exactly does ⊢← do? Also ∘← and similar others
@Adám wow didn't know @ does that
@H.PWiz ⊢← is modified assignment, like += in many languages. ∘← is an unintentional quirk and shouldn't be relied on.
@H.PWiz Here, I'm (ab)using that modified assignment is in-place and so the dfn doesn't localise text.
Because I really want the side-effect of the helper dfn, which is not really the purpose of dfns, but it sure works here ;-)
Mar 21, 2018 7:43 PM
@Adám Okay, and a f←b is a ← a f b?
@H.PWiz Yes.
So now we have:
 text←Scramble text
 something←{
     middle←1↓¯1↓⍵.Match
     FirstOne←⍳∘1
     Rowwise←⍤1
     Classify←∘.∊∘'bdfhkl' 'acemnorsuvwxz' 'gpqy' 'it'
     type←FirstOne Rowwise Classify middle
     Shuffle←{⍵[?⍨≢⍵]}
     text⊣{text⊢←Shuffle@(⍸⍵=type)⊢text}¨type
 }
 text←'\pL+'⎕R something text
@Adám lol can't you just use /
@EriktheOutgolfer Sure, you could do that too:
 text←Scramble text
 something←{
     middle←1↓¯1↓⍵.Match
     FirstOne←⍳∘1
     Rowwise←⍤1
     Classify←∘.∊∘'bdfhkl' 'acemnorsuvwxz' 'gpqy' 'it'
     type←FirstOne Rowwise Classify middle
     Shuffle←{⍵[?⍨≢⍵]}
     text⊣{mask←⍵=type ⋄ ⊢(mask/text)←Shuffle mask/text}¨type
 }
 text←'\pL+'⎕R something text
But really @ is just a shortcut for doing exactly that kind of operations.
@Adám lol I didn't mean replicate, but avoiding the ⊢←-type assignment
like, reducing the function instead of using text and only assigning its result to it
I just inserted the because the function needs a result. We are really abusing a dfn.
@EriktheOutgolfer Ah, ngn style. Right.
Mar 21, 2018 7:51 PM
@Adám actually, that looks more natural to me, maybe with the added too
The last step is of course to put the first and last letters back on the left and right of the result.
@EriktheOutgolfer Like this:
⊃{{⍵[?⍨≢⍵]}@(⍸⍵∊⍺)⊢⍵}/'bdfhkl' 'acemnorsuvwxz' 'gpqy' 'it' text
So here is a much cleaner solution using @EriktheOutgolfer's idea:
 text←Scramble text
 something←{
     middle←1↓¯1↓⍵.Match
     middle←⊃{{⍵[?⍨≢⍵]}@(⍸⍵∊⍺)⊢⍵}/'bdfhkl' 'acemnorsuvwxz' 'gpqy' 'it'middle
     (⊃⍵.Match),middle,(⊃⌽⍵.Match)
 }
 text←'\pL+'⎕R something text
@Adám that deviated a lot from what I thought at first...
I just meant using a reduce to remove the need for the abusive ⊢←
Notice that I've parenthesised (⊃⌽⍵.Match) even though it doesn't need to be. I often do this to emphasise symmetries.
When writing APL (or any language really), it is a good idea to write your code to ease reading.
OK, this has been a somewhat different type of lesson. I hope you found it useful.
 
Conversation ended Mar 21, 2018 at 20:00.