@NoahCristino So you've had your hand at tacit programming. APL also allows more straight forward (I call it "explicit" as opposed to tacit) programming.
The simplest way is to define one-liner (but optionally multi-statement) "dfns". They are one or more statements in {curly braces}. As all other functions, they can be used monadically (prefix) or dyadically (infix).
@NoahCristino Inside curly braces, you refer to arguments explicitly. In tacit functions (normally in round parens) you can only refer to functions applied to the argument(s).
Dfns, as opposed to tacit functions, have their own scope. You can assign to local names, and reuse values that way:
@NoahCristino You may use either, but you'll find that sometimes one style fits better. This is a general philosophy in APL. We provide you with lots of ways to do things according to many paradigms. Mix and match as you see fit!
In a dfn, you can write "guards". They are expressions followed by a : evaluating to 0 or 1. If 1, the expression immediately after the : is the result of the dfn. If 0, execution continues on the next line.
@Adám oookay, you've really got my attention now. What happens if you, for example, try to take the square root of a string. I assume it doesn't work and produces some error indication, but when/how does the interpreter realise it needs to do that if there aren't types?
@Οurous APL doesn't have strings. Instead we use vectors of characters. Arithmetic functions penetrate all structure and so only applies to atomic data. If you feed a characters to power (*) it will throw a domain error.
And atomic data, we call them simple scalars, can basically only be numbers and characters. (There are a couple more "types" but they are more obscure.)
@NoahCristino OK, now write a Fibonacci function. Given N as right argument, find the Nth Fibonacci number.
@Adám Ooh so the entire type system is basically :: Type = Number | Character | Vector Type, where every non-primitive function has a signature like f :: Type Type.. -> Type?
@Οurous I'm not very good at Haskelling, but at least you need to change "Vector" into Array. We prefer phrasing it as follows: All data in APL resides in arrays. An array is a rectangular collection of numbers, characters and arrays, arranged along zero or more axes. Numbers and characters are 0 dimensional arrays, and are refered to as scalars.
@Οurous Note that in APL, a vector of vectors is not the same as a matrix. APL has a much more nuanced array system, which e.g. lets you work with a matrix with 0 rows and 2 columns. Most programming languages cannot do that.
@Οurous If you add more rows, they'll have two columns each. If you add one more column, there'll still be no data, but your sheet now has three columns.
Well, since there are 0 elements in both '' and ⍬, the result will also be 0 elements (just a normal 1d vector with zero elements). Since zero and one are both numeric: the result of ''=⍬ is numeric. Numeric, 1D, 0 elements. That means ⍬≡''=⍬ (⍬ is like []). Now, Dyalog APL has a way of dealing with reduce over empty arrays: it returns the element, that when added to any array, will cause the reduction to remain unchanged
@Οurous Each of → and ⌽ and ↓ in that display form indicate an axis. → is the trailing axis, ⌽ is the axis before that which is a length-0 axis, and ↓ is the first axis. The blank line separates the layers, so you can see there are two layers, no rows, three columns. The apparent rows are only there to tell you that this empty array is "full" of zeros. That is, if you were to coerce elements out of it, they would be zeros. The ~ indicates that the zeros numbers, not characters
BackProp took me longer to write than the entire rest of the contest
I struggled a lot with it, because the problem was not so well specified. I don't think the math/algorithm explained ever ended up being correct, I had to follow some C# XOR net tutorial I found online, hehe
I wanted to write it in a way that worked for multiple hidden layers, and maybe bias somehow, but I felt very out of my depth and out of patience >_<
these are my full set of settings to see if they match with the tensorflow one ('input' (50e3 dd⍴d_data))('target' (1-⍨2×d_lbl∘.=0,⍳9))('weights' (gen_weights dd 30 10))('eta' .1)('iter' 10)('size' 20)
@jslip wait I think I might know why, I don't use the full test set
In Adám's first blog post he discusses employing function keys to assist with debugging – read it at https://www.dyalog.com/blog/2018/09/enhanced-debugging-with-function-keys/
@Cowsquack Well, it won't actually use that much memory if you don't fill your workspace, and if you hit a WS FULL, it'll cut back to where you were before the filling started.
@Adám So, I got this far: {∊((⍳⍴⍵)⍴¨⊂' '),⍤¯1 99⊢¨⍵}⎕D, but it returns the same as {∊((⍳⍴⍵)⍴¨⊂' '),¨⊂⍵}⎕D. I need it to add the spaces between each number in ⎕D, not between multiple ⎕Ds. Any tips?
@ngn Also, this is the kind of stuff I need to learn how to do. I think I'm still too used to imperative and OO languages, so I keep trying to put loop-like functions everywhere instead of working with arrays and matrixes
I had been creating a matrix library for röda inspired by apl functions and operators github.com/kritixilithos/matrix.bil, last time I was working on it, I was thinking how to make röda's streams compatible with apl-like arrays (for example ⍳(10)|sum for 55)
Ugh. I have a solution for this but it fails the test cases where the argument is either ⍬ or has an oob index (both return index errors). @Adám is there any way to return 0 when the index error is encountered?
@ngn I'm not sure how guards work exactly. Also, ⍬ should return true and index errors should return false, that's why I put the error guard in the inner function