Guide to using Functional Paradigmal patterns in Axe
Hello, today I would like to share some things I noticed you can do with Axe to use it in a more high-level functional way. This tutorial assumes you don't know how higher level functional concepts work and walks you through all of them step by step. Axe has limited support for functions, many think, but that's pretty far from the truth. You just can't know all of them from reading a documentation, some of them are either more of reactions that the compiler would do based on its function, or with the help of a little inline assembly. Here are a few things that when used with your program, can make it flow much better and in some cases achieve things that couldn't be done normally with built in features.
Returning Values
This is one of the more simpler concepts that you can draw from functional Axe programming. Basically, when you return a value from a function, you're simply just letting the process of that function represent a value. That value is determined by the function, which does arithmetic and possibly even further computational things to obtain that value. Let's start with this non-functional code for example:
Code:
This can be simply improved like so:
Code:
This is a decent optimization in size, and speed. Plus, you have no need to store the answer value from ADD into a variable, we can just use the call to ADD itself as a value. Why does this work like this? Because HL, the assembly register, is like the Ans with BASIC but with Axe. The parser puts all expressions that were just parsed into HL, so that's why "r2 + r1" returned 10 into HL, which was then used by the calling If statement.
Simple Variable-Attachment Lambdas
What is a Lambda statement? Essentially, it's the most value-like function attainable. It is literally a stand-in for a real value that it returns. Lambdas are very useful in functional programming, but are harder to use in Axe. They come in two forms: Normals, and Procs. I'll start with procs, since Normals are usually attached to a variable (easy to do in HLLs, not easy in Axe, procs are easier to use in straight-up axe). Since they can literally stand into a part of a program in any place, here is an example of a Proc'd expression:
Code:
As you can see, a Proc in Axe is literally just a subroutine used in place of a value exclusively. While that may not be super-useful with small things, it saves a lot of space with constant expression checking, though the speed will generally take a toll so minor that it really woudln't matter.
Normals
Normals can be achieved by attaching a Proc to a variable, so that whenever the variable is accessed its value depends on input parameters. Here is one way of doing so, where you can actually get the value of a variable but in Normallic form using variable indirection and a simple proc:
º
Code:
This Lambda follows Normallic form, but it doesn't completely attach itself to a variable. To do that so it's variable specific, you can do this:
Code:
An alternative to that, where you only use one routine to do both, but it only applies to one:
Code:
Mapping and Folding
Mapping and folding in Functional programming basically are functions that apply to all members of an Array, List, etc. Basically, they loop and fix all numbers one by one until the end of array or the specified length has been reached. An example:
Code:
This above method applies this map to a zero terminated array. To d the same with length termination is a simple difference:
Code:
Folding is almost the same, but it fills in more of the place of a value-function than a performance one. Basically, a Fold is a Map that returns values in the form of any type of object, either in a fixed array leaving the original the same, or even outputting a list of return values in array form afterwards so a programmer can see if certain conditions were met. Examples:
Fixing an array without being destructive, by outputting results to a result array:
Code:
Fixing and checking to see if fixed elements are 10, and output results to an output array:
Code:
Filters
Filters are the next type of higher level functional forms. Filters are simply "checkers" that see if an array has certain elements that fulfill a certain expressional requirement, and returns either the element contents or indices to the passing elements. In many cases with axe, due to limited functional properties already, returning indices is better since you can have more detail on the elements and can do more operations on them, while still being able easily reproduce the exact value of the passing elements. A thing to remember with filter outputs though -- usually, the output for the filter will be an array less than or equal to the size of the inout array -- though in rare cases, with certain passing requirements or double looping checks, they can be larger. But, with the output of filters being so variant in size you need to either take precautions to make sure that if zero is a passing value, you must return the length of the output array. You must also be sure you have error checking for no-match conditions. Anyways, examples:
This code filters the array to see if the elements are equal to 1, and returns indices to the passing elements:
Code:
To return a size of the output array, you can just return B value-style since we're already sure that the output pointer is defined already, you can change it to this:
Code:
Returning multiple arguments
Let's say you want to make a Filter function that assumes that you want the output array to be placed somewhere in memory assigned by the equivalent of a malloc() command. You can return multiple arguments by simply packing all of the returned values into an array of unorganized members. You then return the pointer to that array, and the calling expression can unpack it as needed. Example:
Code:
That covers a lot of functional programming in Axe for now, but there can always be more added. If you have anything to contribute to this set of functional ideals, please post them, and help the effort to bring the Functional Paradigm to Axe a reality by informing others Thanks!
~~Thanks for reading, more coming! Feel free to ask Q&C's, or ask for more content I can add ~~
Hello, today I would like to share some things I noticed you can do with Axe to use it in a more high-level functional way. This tutorial assumes you don't know how higher level functional concepts work and walks you through all of them step by step. Axe has limited support for functions, many think, but that's pretty far from the truth. You just can't know all of them from reading a documentation, some of them are either more of reactions that the compiler would do based on its function, or with the help of a little inline assembly. Here are a few things that when used with your program, can make it flow much better and in some cases achieve things that couldn't be done normally with built in features.
Returning Values
This is one of the more simpler concepts that you can draw from functional Axe programming. Basically, when you return a value from a function, you're simply just letting the process of that function represent a value. That value is determined by the function, which does arithmetic and possibly even further computational things to obtain that value. Let's start with this non-functional code for example:
Code:
sub(ADD,5,5)
If A = 10
Disp "Lol"
End
Lbl ADD
r2 + r1 -> A
Return
This can be simply improved like so:
Code:
If sub(ADD,5,5) = 10
Disp "Lol"
End
Lbl ADD
r2 + r1
Return
This is a decent optimization in size, and speed. Plus, you have no need to store the answer value from ADD into a variable, we can just use the call to ADD itself as a value. Why does this work like this? Because HL, the assembly register, is like the Ans with BASIC but with Axe. The parser puts all expressions that were just parsed into HL, so that's why "r2 + r1" returned 10 into HL, which was then used by the calling If statement.
Simple Variable-Attachment Lambdas
What is a Lambda statement? Essentially, it's the most value-like function attainable. It is literally a stand-in for a real value that it returns. Lambdas are very useful in functional programming, but are harder to use in Axe. They come in two forms: Normals, and Procs. I'll start with procs, since Normals are usually attached to a variable (easy to do in HLLs, not easy in Axe, procs are easier to use in straight-up axe). Since they can literally stand into a part of a program in any place, here is an example of a Proc'd expression:
Code:
Lbl PRC:r1+3:Return
If sub(PRC,rand^4 -> A) = 6
Disp "'tis 6"
Else
Disp "No, it's actually",sub(PRC,A) >Dec
End
As you can see, a Proc in Axe is literally just a subroutine used in place of a value exclusively. While that may not be super-useful with small things, it saves a lot of space with constant expression checking, though the speed will generally take a toll so minor that it really woudln't matter.
Normals
Normals can be achieved by attaching a Proc to a variable, so that whenever the variable is accessed its value depends on input parameters. Here is one way of doing so, where you can actually get the value of a variable but in Normallic form using variable indirection and a simple proc:
º
Code:
If sub(PCV,ºA) = 5
Disp "THIS IS 5."
End
Lbl PCV .The proc for attaching
{r1}r + 5 -> {r1}r
Return
This Lambda follows Normallic form, but it doesn't completely attach itself to a variable. To do that so it's variable specific, you can do this:
Code:
If sub(CA) = 5
Disp "THIS IS 5."
End
Lbl CA .Call A
sub(PCV,ºA)
Return
Lbl PCV
{r1}r + 5 -> {r1}r
Return
An alternative to that, where you only use one routine to do both, but it only applies to one:
Code:
If sub(CA) = 5
Disp "THIS IS 5."
End
Lbl CA
{ºA}r + 5 -> {ºA}r
Return
Mapping and Folding
Mapping and folding in Functional programming basically are functions that apply to all members of an Array, List, etc. Basically, they loop and fix all numbers one by one until the end of array or the specified length has been reached. An example:
Code:
Data(5,6,2,1,0) -> Str1
sub(MAP,Str1)
Lbl MAP
For(A,0,length(r1))
{r1+A} + 5 -> {r1+A}
End
Return
This above method applies this map to a zero terminated array. To d the same with length termination is a simple difference:
Code:
Data(5,6,2,1) -> Str1
sub(MAP,Str1,4)
Lbl MAP
For(A,0,r2)
{r1+A} + 5 -> {r1+A}
End
Return
Folding is almost the same, but it fills in more of the place of a value-function than a performance one. Basically, a Fold is a Map that returns values in the form of any type of object, either in a fixed array leaving the original the same, or even outputting a list of return values in array form afterwards so a programmer can see if certain conditions were met. Examples:
Fixing an array without being destructive, by outputting results to a result array:
Code:
Data(1,2,3,0) -> Str1
L1 -> P . Pointer to result array
sub(FLD,Str1,P)
Lbl FLD
For(A,0,length(r1))
{r1+A} + 5 -> {r2+A}
End
Return
Fixing and checking to see if fixed elements are 10, and output results to an output array:
Code:
Data(1,2,3,0) -> Str1
L1 -> P . Pointer to output array
sub(FLD,Str1,P)
Lbl FLD
For(A,0,length(r1))
{r1+A} + 5 -> {r1+A}
If {r1+A} = 10
1 -> {r2 + A}
Else
0 -> {r2 + A}
End
End
Return
Filters
Filters are the next type of higher level functional forms. Filters are simply "checkers" that see if an array has certain elements that fulfill a certain expressional requirement, and returns either the element contents or indices to the passing elements. In many cases with axe, due to limited functional properties already, returning indices is better since you can have more detail on the elements and can do more operations on them, while still being able easily reproduce the exact value of the passing elements. A thing to remember with filter outputs though -- usually, the output for the filter will be an array less than or equal to the size of the inout array -- though in rare cases, with certain passing requirements or double looping checks, they can be larger. But, with the output of filters being so variant in size you need to either take precautions to make sure that if zero is a passing value, you must return the length of the output array. You must also be sure you have error checking for no-match conditions. Anyways, examples:
This code filters the array to see if the elements are equal to 1, and returns indices to the passing elements:
Code:
Data(1,2,2,1,1,3,0) -> Str1
L1 -> P
sub(FLT,Str1,P)
Lbl FLT
0 -> B
For(A,0,length(r1))
If A*({r1+A}=1}
-> {r2+B}
B++
End
End
Return
To return a size of the output array, you can just return B value-style since we're already sure that the output pointer is defined already, you can change it to this:
Code:
Data(1,2,2,1,1,3,0) -> Str1
L1 -> P
Disp "Size of array: ",sub(FLT,Str1,A) >Dec
Lbl FLT
0 -> B
For(A,0,length(r1))
If A*({r1+A}=1}
-> {r2+B}
B++
End
End
B
Return
Returning multiple arguments
Let's say you want to make a Filter function that assumes that you want the output array to be placed somewhere in memory assigned by the equivalent of a malloc() command. You can return multiple arguments by simply packing all of the returned values into an array of unorganized members. You then return the pointer to that array, and the calling expression can unpack it as needed. Example:
Code:
Data(1,2,1,2,3,1) -> Str1
sub(MRF,Str1) -> P
Disp {P+2} >Dec," Passing elements found, which are at indices: ",i
For(A,0,{P}r)
Disp {{P}r+A} >Dec,", "
End
Lbl MRF
... CALL MALLOC COMMAND
AND DELEGATE SOME
MEMORY AND GIVE A
POINTER IN P ...
0 -> B
For(A,0,length(r1))
If A*({r1+A}=1}
-> {P+B}
B++
End
End
... CALL MALLOC COMMAND
AND DELEGATE SPACE THAT
IS B BYTES LONG, POINTED TO
BY Q ...
P -> {Q}r . Load P into first two bytes
B -> {Q+2} . Load length int 3rd byte
Q . Return pointer to return array
Return
That covers a lot of functional programming in Axe for now, but there can always be more added. If you have anything to contribute to this set of functional ideals, please post them, and help the effort to bring the Functional Paradigm to Axe a reality by informing others Thanks!
~~Thanks for reading, more coming! Feel free to ask Q&C's, or ask for more content I can add ~~