Author Topic: [Tutorial] Edition 2: Using Axe to its full functional form λ  (Read 21092 times)

0 Members and 1 Guest are viewing this topic.

Ashbad

  • Guest
I - Introduction

Hello, Ashbad again.  I'm back to rewrite my original tutorial to using functions and other entities found in functional programming in Axe.  Disregard the old version now; this one teaches you how to use the new functional features of Axe 1.0.0 and higher, whereas the old one was modeled to hackishly attempt some simple functional workings in Beta versions of Axe, 0.5.3 and lower.

This version is completely rewritten and uses now text from the first tutorial, so that I can start fresh, as all the actual code content shown must be fresh as well.  This time I will try to explain things a little better, and even use examples comparing Axe code to Ruby/Python code so that people who have used higher level functional ideals in computer languages before can simply use this as a reference to see the Axe equivalent for something.

With that, good luck with the reading, and feel free to post questions below, since this is a lot of material to cover and I'm covering it slightly fast, so don't feel awkward in doing so.

Note: the first few sections are really basic to intermediate-to-advanced Axe programmers, so feel free to skip them if you already know what subroutines are and how to return values.


II - Simple Functions

What are functions?  Functions, called subroutines in Axe, are essentially like the functions seen in math classes like Algebra I and II.  Functions receive a list of variables, numbers, or expressions, called arguments, in a list, and then use the input values to determine an outcome value.  More simply for those who said "LOL MAN, ENGRISH PLZ", I'll provide a code example, since it is important to understand how subroutines work, otherwise you'll be all LOLWAT later on in this tutorial.  Here is an example of a subroutine's code body, the place where the output value of the function is determined:

Code: [Select]
Lbl CAT
  r1+r2 -> A
Return

This is a standard subroutine, which starts with a name, in this CAT, some code inside, and a Return which ends the declaration.  The values r1 - r6 are variables that represent the passed in arguments.  These are argument variables, which means their values are local to the subroutine body, which in English means that they only have any significance when they're used inside of the routine's code body.  Here is how we can call routine CAT:

Code: [Select]
CAT(5,6)
When we run this, A will be equal to 11.  Why is this?  Because the first argument, 5, is stored into r1, same as 6 and r2; in the code body of this routine we called, we stored the value of argument variable 1 plus the value of argument variable 6 and stored it into A. If we did this all inline (all of the code was done without routines, and we added in the formula directly into the code instead), it would look like this:

Code: [Select]
5 + 6 -> A
These subroutines are the basis for all Axe functional programming, and all functional programming in general.  By now you should understand how they basically work, so it's time to start stepping it up a notch in the learning curve, and talk about returned values.


III - Returning Values

Sometimes, you'll want to be able to use a subroutine as part of an expression, but don't want to have to store the answer to a variable every time you want to use the output value of the routine.  In the last section, we used a really simple subroutine, CAT, to add two arguments together and output the value into A.  What if you are already using A and the rest of the variables, or want to store the output to an arbitrary variable instead of having to write different subroutines each time?

This is where Returned Values come into play.  But before I go directly into this concept, I'll explain a natural phenomenon of Axe.  In Axe, each expression you put in your code will eventually have a final value, such as 5+6*3, which will evaluate to 33.  Where is this expression value stored?  The latest value that has been a result of an expression is stored in an Assembly register called HL, a 16 bit general purpose (though commonly used with pointers in Assembly) register that Axe uses as a placeholder for values though expressions.  For BASIC programmers, here is a quote that will help you understand the purpose of HL:

Quote from: runer
HL is like the Ans of Axe.

Like you can use Ans in BASIC, you can use HL in Axe, though not directly as a variable.  Because Axe works this way, Returning values from expressions is entirely possible.  Here is a change to our original routine, CAT:

Code: [Select]
Lbl CAT
  r1+r2
Return

Notice here the only difference is that we took away the ->A part.  Why did we do this?  Instead of storing the result of r1+r2 to A, we pass it only to HL instead.  Let's see what we can now do differently with this, now that A is no longer destroyed by the routine:

Code: [Select]
CAT(5,6)+A -> B
With the old example, the inline version would look like this:

Code: [Select]
5 + 6 -> A + A ->B
The result is 22, since we destroy the original value of A, and when we add it again we're just adding it's new value to itself, and storing the final result into B.  With out new code body for CAT, here's what it looks like inline now:

Code: [Select]
5 + 6 + A -> B
Whatever was stored in A before is now left intact; therefore, B will now hold 11 plus whatever was originally in A.

Here is a computer language equivalent of what I just showed above:

Code: [Select]
def CAT(arg1, arg2)
  return arg1+arg2
end

B = A + CAT(5, 6)

Keep in mind, HL is constantly being changed every expression, so only the very last expression of the code body for a subroutine trying to act like a function (a subroutine which simply is a stand in for a value, and it's output is determined completely by the input arguments) will be passed as the output of the function.

This is a decent amount of information for people new to subroutines and functions to process in one day, and if you genuinely learned all of what I just taught for the first time ever from reading this just now, practice with what I told you and make sure you have the concepts down perfectly before continuing on.  I suggest you stop reading for now, let it soak in for a little while (a day, perhaps) before continuing on, the following will just make you confused.  For those who totally understand this already, read ahead.


IV - Fun with Addresses

The only thing we've talked about concerning how to call functions are labels.  Up until axe 1.0.0, this was the only way we could call them.  We now have a new way to call themes well: by address :).  When we call a function by address, we can do a whole new slew of tricks previously impossible before the addition of this wonderful feature.  Here is the syntax for calling a function this way:

Code: [Select]
(ADDRESS)(ARGUMENTS)
Which is actually pretty simple design.  How do we get the address of a label, so we can maybe do an offset to the beginning of the function?  Putting the list token (L; note in my examples I use a big L with a small V in front of it to denote the little L, heads up) in front of the name in an expression.  Here's a new way to call CAT, but in this form:

Code: [Select]
(LvCAT)(5,6)
.Same as:
CAT(5,6)

Overall, It's a decently simple concept to work with.  We build upon this later when we work with closures, lambdas, etc.  Here's another few tricks you can do with getting the addresses of labels:

Simple SMC with copying one function to another (the labels with the E at the end mean they were put right after the return statement in the code body of the corresponding function):

Code: [Select]
Copy(LvCAT,LvDOG,LvCATE-LvCAT)
Finding the size of a routine:

Code: [Select]
Disp LvCATE-LvCAT >Dec
In computer languages you usually don't get this type of freedom, not even in lower level functional languages (with a few exceptions), so no computer language references here.

If you understand this and think it's an easy concept, good.  It has to be if you're going to go further in this tutorial; it is absolutely fundamental to everything else coming up.  Hence, I will now introduce you to our new friends, Lambdas.


V - Lambdas

Now, here is the part that everyone gets confused with.  What is a lambda?  A Greek character?  A function that is very special in use?  An interesting feature of functional programming?  Something you'll never use?  It's the first three ones ;-).  It is indeed a Greek character, which in token form in an Axe program, takes the place of log(.  It is indeed a function, and it is more than just a simple one at that, so yes, special.  And, it is an interesting feature of functional programming.  I don't find it a useless feature though, and you'll see why I think that.

A Lambda, or anonymous function, is a function that has no label name whatsoever.  The only way you can access or call a lambda is through it's address, using techniques similar to those we just learned above.  A lambda can also be used inline with an expression, and called in the same line it was initialized (though, this is optional).  Lambdas are useful, especially when we go into higher-level types of functions like maps, folds, and filters.

Since that might confuse some people, here is our first example of a lambda:

Code: [Select]
λ(r1+r2)(5,6)
what does this do?  It looks confusing, but it actually isn't.  The first set of parenthesis after the lambda symbol is actually the code block for the anonymous function.  Code blocks in lambdas do not end with a return statement; it actually throws an error.  Rather, their last expression of code is automatically returned into HL.  The second set of parenthesis is the argument list, which is straightforward now that you know what that is.  This line of code simply returns 11, as it initializes the lambda expression and calls it immediately.

Here is how to store the address of a lambda for later use:

Code: [Select]
λ(r1+r2) -> L
When we don't add the parenthesis after the lambda expression, we simply just return the address of the lambda into HL, which we then stored here into 16 bit variable L.  To call this lambda again:

Code: [Select]
(L)(5,6)
Lambdas are very helpful for quick evaluation of functions, and can be easily stored into a list and have the correct one called for evaluation of an expression based on the current program conditions.  They're also useful inside of variable-passed loops and inside other functions and even other lambdas, which I will talk about soon.

In computer languages, the second example with the variable L is called Lambda attachment, where the variable L isn't just a reference to the lambda, but changing the value of L requires calling the lambda with arguments, like so, in Ruby:

Code: [Select]
L = lambda { | arg1, arg2 | arg1+arg2 }
L.call(5,6) #returns 11

This is very similar to what we did in Axe, but the axe version is a lot more primitive, since it is only storing the address of the function into L, whereas the Ruby one does that and a few more thing, which gives it more control.  So, computer programmers, don't confuse the exact use of variable attachment between computer languages and Axe, you might find yourself doing things wrong in some cases.


VI - Closures and Currying

I know, "LOLOMG", those two terms sound stupid, right?  They'll sound a lot cooler once you realize how awesome the two concepts are ;-).  Both of these concepts build upon the idea of using lambdas.  Both of these concepts are really, really similar, but are different based only on the entity they're used within.

To start, well use closures.  Closures are functions that are embedded inside of other functions;  the embedded functions share the same argument variables as the outside function, as they get passed along in the embedded argument list.  There are two types of closures in Axe -- independent and dependent.  Independent ones are their own functions and can be called on their own; but when the main function is called, their arguments are the same as those of the larger function.  An example:

Code: [Select]
Lbl CAT
  r1+r2->r4
  DOG(r1,r2,r3,r4)
  Goto DOGE
  Lbl DOG
    r4+r3
    Return
  Lbl DOGE
  -> r1
  Return
Lbl CATE

Notice how when DOG is called, the arguments it is given are the exact same as what will be passed to CAT.  Like I said above, this is how closures will usually act when taking operands.  Dependent Closure's use are rare, but don't forget about them since they can still be lifesaving in terms of optimization when you need to only call part of a routine.  They are also messy to implement, which is why dependent closures usually take precedence.  Independent ones are closures that cannot be called from outside of the function; these are usually implemented via lambdas:

Code: [Select]
Lbl CAT
  r1+r2->r4
  λ(r4+r3)(r1,r2,r3,r4)->r1
  Return
Lbl CATE

as you can see, a lot cleaner than dependent ones :-) which is a big upside for organization and optimization.  The only downside is that they can't be called from outside the function, but that's usually okay in 99% of circumstances they're used.

Keep in mind using a lambda for so ethane that simple is a bit kooky, since without it it would be even more optimized.  I just use it as a light-hearted example :-).

Currying is very very similar to this.  A curry is a lambda within a lambda.  They share the same arguments in most cases, and the inner lambda helps the evaluation of the outer lambda.  Again, another silly example:

Code: [Select]
λ(r1*(λ(r1+r2)(r1,r2)))(r1,r2)

VII - Higher-level Functions

In this section, we'll be covering three specific types of functions, which are Maps, Folds, and Filters.  These three types of functions are called higher-level because they are usually made to take other functions (usually lambdas) as parameters, which they use to apply a rule on a set  of data, such as an array or list (we'll be working with an array of 8 bit values here)

The first one up -- mapping.  Mapping is the simplest of the three -- a map will take parameters for a function to apply to a set of data, which is a second parameter in most cases.  Here is the code body for a really simple map:

Code: [Select]
Lbl MAP
  For(A,r2,r2+r3)
    (r1)({A}) -> {A}
  End
Return

This one will take three parameters -- an address to a function (or a lambda since they will return an address), a starting address for our array, and the length of the array.  The first argument, the function, will take the value of the current index position in a loop over the array, apply the expression, and return it so it can be stored back into the array.  Here is an example of calling this simple map:

Code: [Select]
MAP(λ(r1*2),L1,50)
What this will do is multiply all of the first 50 bytes in L1 by 2, and store them back again.

Next up is folding.  Folding is somewhat like mapping, but it'll return something, such as a status or a pointer to a fixed array, after it runs through as a modified map.  Here is an example of a Fold:

Code: [Select]
Lbl FOLD
  r4 -> B
  For(A,r2,r2+r3)
    (r1)({A}) -> {B}
    B++
  End
  r4
Return

This is a really, really simple fold that maps the input function over the range specified, but it takes a fourth argument to specify where to put the fixed data.  It doesn't affect the elements of {r2} through {r2+r3}, but it does scan them and store the results starting at {r4}.  Since it is a fold, it needs to return something, so at the end it passes the original pointer to the new data into HL.  Here is our call:

Code: [Select]
FOLD(λ(r1+r2),L1,50,L2)
The last I'll discuss here is Filtering.  Filters take in a Function like the first two did, but the function in this case is testing to see if an element meets an expression; if it does, it will store the index place in an output array.  The output array is at most the size of the original array, and in many cases smaller if elements don't meet the expression.  It's also good to add one to each of the indices return, so we can null terminate the returned array.  Here is our simple filter function:

Code: [Select]
Lbl FILT
  r4 -> B
  For(A,r2,r2+r3)
    If (r1)({A})
      +1-> {B}:B++
    End
  End
  0 -> {B}
  r4
Return

We can call it like this:

Code: [Select]
FILT(λ(r1=5),L1,50,L2)
This call will return a pointer to L2, which will contain the indices of all elements plus 1 within the first 50 bytes of L1 that equal 5, null terminated.


VIII - Closing

I hope this taught everyone a little something about Axe functional programming; I tried to make it for all levels of experience, so everyone can get something out of it.  I had a fun time writing this (somewhat sarcastic when saying this, I did it all in the Notes app on my iPad and was a pain to type) and I hope you had a fun time reading this.  With that, salut, and I'm off to work soon so I wont be able to see any hate mail here for about 11 hours ;-)


IX - comments and all that crap

Questions?  Comments?  Feel free to post them below in this thread.  If you want some heads on help, feel free to shoot me a PM here.  And, if you want me to cover another concept, post what you want here and I can add something on it most likely ;-)
« Last Edit: July 17, 2011, 09:22:33 pm by Ashbad »

Offline ztrumpet

  • The Rarely Active One
  • CoT Emeritus
  • LV13 Extreme Addict (Next: 9001)
  • *
  • Posts: 5712
  • Rating: +364/-4
  • If you see this, send me a PM. Just for fun.
    • View Profile
Re: [Tutorial] Edition 2: Using Axe to its full functional form λ
« Reply #1 on: July 16, 2011, 10:44:07 am »
Okay, this is awesome.  I understand lambdas now. :D  Thanks for the great tutorial, Ashbad! ;D

Offline Deep Toaster

  • So much to do, so much time, so little motivation
  • Administrator
  • LV13 Extreme Addict (Next: 9001)
  • *************
  • Posts: 8217
  • Rating: +758/-15
    • View Profile
    • ClrHome
Re: [Tutorial] Edition 2: Using Axe to its full functional form λ
« Reply #2 on: July 16, 2011, 11:59:27 am »
Awesome tutorial. I'm still getting used to all this new Axe syntax o.o




Offline Michael_Lee

  • LV9 Veteran (Next: 1337)
  • *********
  • Posts: 1019
  • Rating: +124/-9
    • View Profile
Re: [Tutorial] Edition 2: Using Axe to its full functional form λ
« Reply #3 on: July 16, 2011, 12:00:02 pm »
Nice work!

A question:
What are closures useful for?  What can you do with them?
My website: Currently boring.

Projects:
Axe Interpreter
   > Core: Done
   > Memory: Need write code to add constants.
   > Graphics: Rewritten.  Needs to integrate sprites with constants.
   > IO: GetKey done.  Need to add mostly homescreen IO stuff.
Croquette:
   > Stomping bugs
   > Internet version: On hold until I can make my website less boring/broken.

Offline ztrumpet

  • The Rarely Active One
  • CoT Emeritus
  • LV13 Extreme Addict (Next: 9001)
  • *
  • Posts: 5712
  • Rating: +364/-4
  • If you see this, send me a PM. Just for fun.
    • View Profile
Re: [Tutorial] Edition 2: Using Axe to its full functional form λ
« Reply #4 on: July 16, 2011, 12:13:36 pm »
Nice work!

A question:
What are closures useful for?  What can you do with them?
Optimize.  Basically part of your routine is a common task that you have to do a lot, so you just put that in a subroutine so other spots in your entire program can use it other than just the routine that the code itself is in.  Or at least that's what I gathered from the tutorial. ;D

Offline calcdude84se

  • Needs Motivation
  • LV11 Super Veteran (Next: 3000)
  • ***********
  • Posts: 2272
  • Rating: +78/-13
  • Wondering where their free time went...
    • View Profile
Re: [Tutorial] Edition 2: Using Axe to its full functional form λ
« Reply #5 on: July 16, 2011, 02:28:11 pm »
Code: [Select]
Lbl HACK
  r1+r2
  Asm(E5)
  r2*r1
Return
No. Bad. Don't do that. That code will jump to the address r1+r2 with hl=r2*r1 because ret/Return takes the address that's most recently been pushed. What you instead want to do is replace Asm(E5) with Asm(E3E5) (ex (sp),hl \ push hl) and do that for all extra values. That way the return address is in the right place when you return. When the subroutine does return Asm(E1) is still the proper way to get those extra values off of the stack.
"People think computers will keep them from making mistakes. They're wrong. With computers you make mistakes faster."
-Adam Osborne
Spoiler For "PartesOS links":
I'll put it online when it does something.

Offline Runer112

  • Project Author
  • LV11 Super Veteran (Next: 3000)
  • ***********
  • Posts: 2289
  • Rating: +639/-31
    • View Profile
Re: [Tutorial] Edition 2: Using Axe to its full functional form λ
« Reply #6 on: July 16, 2011, 02:28:37 pm »
This is a very extensive and well-written tutorial. But I have some questions/concerns about some of these topics and code structures.


  • Lambdas in Axe are, for all intents and purposes, slightly bloated subroutines (due to the jump past the routine). I realize that lambdas have other qualifying features like ease of inserting inline, but I feel that the fact that they produce slightly larger code than a standard subroutine is worth being mentioned.


  • Regarding closures and currying, as far as I can tell, code would be more optimized simply without these techniques. I think code also looks cleaner without the unnecessary nesting. If you can give me a counter-example, I would love to see it. But regarding the examples you used, compare these:

Code: (Independent closure; 54 bytes) [Select]
Lbl CAT
  r₁+r₂→r₄
  DOG(r₁,r₂,r₃,r₄)
  Goto DOGE
  Lbl DOG
    r₄+r₃
    Return
  Lbl DOGE
  →r₁
  Return
Lbl CATE
   
Code: (Two separate routines; 51 bytes) [Select]
Lbl CAT
  r₁+r₂→r₄
  DOG(r₁,r₂,r₃,r₄)
  →r₁
  Return
Lbl CATE

Lbl DOG
  r₄+r₃
  Return
Lbl DOGE

Code: (Currying; 62 bytes) [Select]
λ(r₁*(λ(r₁+r₂)(r₁,r₂)))(r₁,r₂)
   
Code: (No currying; 38 bytes) [Select]
λ((r₁+r₂)*r₁)(r₁,r₂)


  • A big reason why the example above without currying is so much smaller is because it omitted an argument list due to one of the functions being eliminated. This is something that you should do in multiple other places as well. Calling a function with the r-vars as arguments is redundant, because all it does is load the r-vars and then save them back where they already were. For example, λ((r₁+r₂)*r₁)(r₁,r₂) could be λ((r₁+r₂)*r₁)() to save 12 bytes, and DOG(r₁,r₂,r₃,r₄) could simply be DOG() to save a massive 24 bytes.


VIII - Returning multiple values

WARNING -- THE FOLLOWING PROCEDURE IS POSSIBLY DANGEROUS IF USED INCORRECTLY.
  • (Ninja'd by calcdude84se) Your procedure is dangerous if used at all. You push the second value to return on top of the return address, so the Return will read the wrong value and almost certainly crash or otherwise negatively affect your calculator. You need to keep the return address at the top of the stack and push extra return values under it:

Code: [Select]
Lbl HACK
  r₁+r₂
  Asm(E3E5)    . ex (sp),hl \ push hl
  r₂*r₁
Return



Also, a suggestion to make code look cleaner. Fish around in this for special characters on the calculator:
Spoiler For Special Characters:


ʟ
L₁
L₂
L₃
L₄
L₅
L₆
r₁
r₂
r₃
r₄
r₅
r₆
Y₁
Y₂
Y₃
Y₄
Y₅
Y₆
Y₇
Y₈
Y₉
Y₀
°
∆List(



·


⁻¹
²
³
√(
³√(
ˣ√


ʳ
►Dec
►Frac
►Char
►DMS
►Tok
►Rect
►Hex
θ
α
β
γ
Δ
δ
ε
λ
μ
π
ρ
Σ
Φ
Ω

χ
σ
τ



ß
ˣ




×


ȳ

« Last Edit: July 16, 2011, 02:29:29 pm by Runer112 »

Ashbad

  • Guest
Re: [Tutorial] Edition 2: Using Axe to its full functional form λ
« Reply #7 on: July 16, 2011, 11:08:11 pm »
thanks for the feedback :) glad you liked it.  I didn't know lambdas were slightly bigger, thanks for the knowledge.  Also, independent closures are usually useless.  I personally never find any use of them, but I put it there more because there are people who are used to them in computer languages like Haskell and others, so it put it up more as a reference for them so they could feel at home still.  I don't have any example off-hand in Axe where currying or dependent closures are useful, but in Ruby they are great and I love using 'em for things like this:

Code: [Select]
def apply_embedded_ruleset(_junction, _module_rule=Junction::NIL, &optional_output_map=nil);using Junction,Superpos
  lambda_a = Array.new(_junction.coelements) raise Junction::NotAJunctionException assure (_junction.to_j raise Junction::NotAValidTransformTypeException)
  delta_list = lambda_a.size
  lambda_a.inject(Superpos.fold_by?(_junction,Proc.new(no_block,nil).type)).slice(lambda_a.uniq+
    (delta=Superpos.find_types(_junction,Proc.new(no_block,nil)).to_a.size.to_i),delta+1)#clean
  if block_given? and passed_args==Junction.any[1,2]
    index=0;delta=nil;while index<(_junction.coelements+1)
      yield lambda_a.for_each{ | lambda | delta_list.at(index) ~=>
        lambda.call(_junction.give_coelement index) }.pack rescue $last assure index++;end
  else
    delta=nil
    return _junction.for_all{ | value, index | value = lambda_a.for_each { | lambda, value, index | lambda.call(
(optional_output_map)?(optional_output_map.at(index)):(_junction.give_coelement index)) }.pack rescue $last;end
  end
  raise UnknownException.new("Random thing happened, that was weird.")
end

In that case, it was rather useful.  It was part of my module Quantum::Superpos that wasn't attached to any class definition.  It takes a common Junction, filters out any lambdas within it, apply all of those lambdas concurrently to every element of the same junction, and return self.  Multiple usage of closures and curries, though mostly non-explicit.  I don't know if there would be a great usage of closures and curries in Axe, but don't take those examples I gave seriously; I literally just gave those because they showed the concept without being difficult to understand.
     
Edit: ew also that code I wrote is indeed ugly, Ruby is considered a beautiful language but I keep on bothering beauty in order to demand performance and small code size.  Sorry Matz :(

Also w00ps on the Assembly part :P I'll fix that.
« Last Edit: July 17, 2011, 08:14:09 am by Ashbad »

Offline Anima

  • LV4 Regular (Next: 200)
  • ****
  • Posts: 133
  • Rating: +4/-0
    • View Profile
Re: [Tutorial] Edition 2: Using Axe to its full functional form λ
« Reply #8 on: July 17, 2011, 06:04:27 am »
Awesome tutorial, thanks Ashbad. :)


Sorry for my bad English. I'm German.

Ashbad

  • Guest
Re: [Tutorial] Edition 2: Using Axe to its full functional form λ
« Reply #9 on: July 17, 2011, 09:32:58 pm »
Glad people liked it :)

Two things:

Got rid of the returning multiple values section and bumped down roman numerals past it.

Would someone please add this new edition of the tutorial to the Tutorials section please?

Offline Scipi

  • Omni Kitten Meow~ =^ω^=
  • LV10 31337 u53r (Next: 2000)
  • **********
  • Posts: 1547
  • Rating: +192/-3
  • Meow :3
    • View Profile
    • ScipiSoftware
Re: [Tutorial] Edition 2: Using Axe to its full functional form λ
« Reply #10 on: July 18, 2011, 10:50:38 am »
Thanks for this. I'm going to start learning Axe since I have a good grasp of pointers due to using them a lot in C++, and this tutorial really helps with learning the basic syntax. XD

Imma Cat! =^_^= :3 (It's an emoticon now!)
Spoiler For Things I find interesting:
Spoiler For AI Programming:
Spoiler For Shameless advertising:

Spoiler For OldSig:





Spoiler For IMPORTANT NEWS!:
Late last night, Quebec was invaded by a group calling themselves, "Omnimaga". Not much is known about these mysterious people except that they all carried calculators of some kind and they all seemed to converge on one house in particular. Experts estimate that the combined power of their fabled calculators is greater than all the worlds super computers put together. The group seems to be holding out in the home of a certain DJ_O, who the Omnimagians claim to be their founder. Such power has put the world at a standstill with everyone waiting to see what the Omnimagians will do...

Wait... This just in, the Omnimagians have sent the UN a list of demands that must be met or else the world will be "submitted to the wrath of Netham45's Lobster Army". Such demands include >9001 crates of peanuts, sacrificial blue lobsters, and a wide assortment of cherry flavored items. With such computing power stored in the hands of such people, we can only hope these demands are met.

In the wake of these events, we can only ask, Why? Why do these people make these demands, what caused them to gather, and what are their future plans...

Ashbad

  • Guest
Re: [Tutorial] Edition 2: Using Axe to its full functional form λ
« Reply #11 on: July 18, 2011, 11:59:59 am »
Glad you liked it :) this should cover everything concerning subroutines and functions, so you will only have to print out this one ;D

Ashbad

  • Guest
Re: [Tutorial] Edition 2: Using Axe to its full functional form λ
« Reply #12 on: July 19, 2011, 01:01:40 pm »
I would like to point out that my definition of currying is generally correct for most modern languages, but for purely-functional languages like Haskell, currying is a trick to allow multiple parameters for single-parameter functions, so that you take your first parameter, and return a new function that takes the second parameter.  Like so, in Haskell:

Code: [Select]
mult :: Int -> (Int -> Int)
mult a b = a * b

So that mult takes a parameter, returns a function, and then the second argument is passed to the returned function.  In axe, functions take more than one parameter, and therefore aren't true functions, unless you consider the parameter list a variable tuple, which would make it functional again.  Here is what Haskell Currying looks like in Axe:

Code: [Select]
Lbl MULT
  r1->r2
  λ(r1*r2)
Return

(MULT(5))(10)

I'm gonna edit my tutorial to express haskell currying instead of what it is called in other languages.
« Last Edit: July 19, 2011, 01:11:34 pm by Ashbad »

Offline Quigibo

  • The Executioner
  • CoT Emeritus
  • LV11 Super Veteran (Next: 3000)
  • *
  • Posts: 2031
  • Rating: +1075/-24
  • I wish real life had a "Save" and "Load" button...
    • View Profile
Re: [Tutorial] Edition 2: Using Axe to its full functional form λ
« Reply #13 on: July 19, 2011, 03:25:04 pm »
By the way, just thought I'd mention since this is all about programming style, I think the code looks better and is more intuitive to have the expression you are returning on the same line as the return instead of the previous one:

Code: [Select]
Lbl MULT
  r1->r2
Return λ(r1*r2)

I notice a lot of people still aren't using that form.  I would enforce it if it were possible, but that's an impossible check to make.
___Axe_Parser___
Today the calculator, tomorrow the world!

Ashbad

  • Guest
Re: [Tutorial] Edition 2: Using Axe to its full functional form λ
« Reply #14 on: July 19, 2011, 03:26:54 pm »
I didn't know that was valid.  The Return token doesn't end with a parens or a space, so I assumed it didn't work like that.  Plus, adding in your own spaces is something I find messy :/