Omnimaga

Calculator Community => TI Calculators => Axe => Topic started by: Ashbad on July 16, 2011, 10:22:58 am

Title: [Tutorial] Edition 2: Using Axe to its full functional form λ
Post by: Ashbad on July 16, 2011, 10:22:58 am
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 ;-)
Title: Re: [Tutorial] Edition 2: Using Axe to its full functional form λ
Post by: ztrumpet on July 16, 2011, 10:44:07 am
Okay, this is awesome.  I understand lambdas now. :D  Thanks for the great tutorial, Ashbad! ;D
Title: Re: [Tutorial] Edition 2: Using Axe to its full functional form λ
Post by: Deep Toaster on July 16, 2011, 11:59:27 am
Awesome tutorial. I'm still getting used to all this new Axe syntax o.o
Title: Re: [Tutorial] Edition 2: Using Axe to its full functional form λ
Post by: Michael_Lee on July 16, 2011, 12:00:02 pm
Nice work!

A question:
What are closures useful for?  What can you do with them?
Title: Re: [Tutorial] Edition 2: Using Axe to its full functional form λ
Post by: ztrumpet 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
Title: Re: [Tutorial] Edition 2: Using Axe to its full functional form λ
Post by: calcdude84se 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.
Title: Re: [Tutorial] Edition 2: Using Axe to its full functional form λ
Post by: Runer112 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.





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₂)




VIII - Returning multiple values

WARNING -- THE FOLLOWING PROCEDURE IS POSSIBLY DANGEROUS IF USED INCORRECTLY.

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
θ
α
β
γ
Δ
δ
ε
λ
μ
π
ρ
Σ
Φ
Ω

χ
σ
τ



ß
ˣ




×


ȳ

Title: Re: [Tutorial] Edition 2: Using Axe to its full functional form λ
Post by: Ashbad 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.
Title: Re: [Tutorial] Edition 2: Using Axe to its full functional form λ
Post by: Anima on July 17, 2011, 06:04:27 am
Awesome tutorial, thanks Ashbad. :)
Title: Re: [Tutorial] Edition 2: Using Axe to its full functional form λ
Post by: Ashbad 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?
Title: Re: [Tutorial] Edition 2: Using Axe to its full functional form λ
Post by: Scipi 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
Title: Re: [Tutorial] Edition 2: Using Axe to its full functional form λ
Post by: Ashbad 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
Title: Re: [Tutorial] Edition 2: Using Axe to its full functional form λ
Post by: Ashbad 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.
Title: Re: [Tutorial] Edition 2: Using Axe to its full functional form λ
Post by: Quigibo 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.
Title: Re: [Tutorial] Edition 2: Using Axe to its full functional form λ
Post by: Ashbad 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 :/
Title: Re: [Tutorial] Edition 2: Using Axe to its full functional form λ
Post by: Quigibo on July 19, 2011, 03:30:42 pm
Unfortunately I can't add an extra space to the token because of ReturnIf.  I don't think adding in a space is messy, and you can ignore the space if you want, its still valid.
Title: Re: [Tutorial] Edition 2: Using Axe to its full functional form λ
Post by: Ashbad on July 19, 2011, 03:31:44 pm
Good point.  But I prefer the old style better ;) even if it is valid the other way.
Title: Re: [Tutorial] Edition 2: Using Axe to its full functional form λ
Post by: LincolnB on July 19, 2011, 03:41:52 pm
Quote
Plus, adding in your own spaces is something I find messy

Really? I think it's great unless you're trying to indent all of your if statements and loops were there's like thirteen nested layers
Title: Re: [Tutorial] Edition 2: Using Axe to its full functional form λ
Post by: Ashbad on July 19, 2011, 03:58:41 pm
Quote
Plus, adding in your own spaces is something I find messy

Really? I think it's great unless you're trying to indent all of your if statements and loops were there's like thirteen nested layers

Well, I like to think of it as being a last equation -> outside world notation rather than a give equation notation.  I also like to think of Return as an end for a def statement, since explicit routines are only created with a label with no ending keyword, an adding something past that would make it feel akward.
Title: Re: [Tutorial] Edition 2: Using Axe to its full functional form λ
Post by: LincolnB on July 19, 2011, 04:14:24 pm
Well, I like to think of it as being a last equation -> outside world notation rather than a give equation notation.

What in the world do you mean?
Title: Re: [Tutorial] Edition 2: Using Axe to its full functional form λ
Post by: Ashbad on July 19, 2011, 04:20:43 pm
What I mean is that I think of returning values in Axe in a more functional way, so that the last expression is the overall output value for the entire function.  That way, I only use Return for ending the definition ending.
Title: Re: [Tutorial] Edition 2: Using Axe to its full functional form λ
Post by: LincolnB on July 19, 2011, 04:32:47 pm
Oh, all right.
Title: Re: [Tutorial] Edition 2: Using Axe to its full functional form λ
Post by: ztrumpet on July 19, 2011, 04:55:40 pm
What I mean is that I think of returning values in Axe in a more functional way, so that the last expression is the overall output value for the entire function.  That way, I only use Return for ending the definition ending.
Yeah, I tend to think of it this way as well.
Title: Re: [Tutorial] Edition 2: Using Axe to its full functional form λ
Post by: nemo on July 19, 2011, 07:27:36 pm
quick question, what's the advantage of currying in axe? as runer pointed out, it takes up more memory, and in my opinion, looks messier
Title: Re: [Tutorial] Edition 2: Using Axe to its full functional form λ
Post by: Ashbad on July 19, 2011, 07:41:27 pm
Well, depends on what form of currying you're talking about.  For non-pure-functional currying, its useful because it means in general that you're just passing parameters to explicit or non-explicit functions called or even defined and then called inside of the function.  For Haskellian currying, there is no definite use, unless you want to pass a very, very long list of parameters.
Title: Re: [Tutorial] Edition 2: Using Axe to its full functional form λ
Post by: selectcoaxial on July 24, 2011, 07:58:48 am
beginner question, how do you get r1 and r2 on the graphics calculator?
Title: Re: [Tutorial] Edition 2: Using Axe to its full functional form λ
Post by: mrmprog on July 24, 2011, 08:02:29 am
Vars->Y-Vars->Polar
Hope that helps.
Title: Re: [Tutorial] Edition 2: Using Axe to its full functional form λ
Post by: Ashbad on July 24, 2011, 08:37:20 am
You can have up to 6, using tokens r1-r6.
Title: Re: [Tutorial] Edition 2: Using Axe to its full functional form λ
Post by: Munchor on July 24, 2011, 01:14:13 pm
A subroutine is called like:

Code: [Select]
sub(DD, A, "HELLO", C, 5)
In this example, A is r1, "HELLO" is r2, C is r3, 5 is r4.

I once needed more arguments...
Title: Re: [Tutorial] Edition 2: Using Axe to its full functional form λ
Post by: Ashbad on July 28, 2011, 09:33:52 pm
So, is this just going to never be in the new "Tutorials" section?  I've asked like 5 times in 3 separate threads, and I'm pretty much forced to give up all hope.  People who want to see this will have to follow the new "this is outdated link" in the old tutorial, I guess :/

Edit:

A subroutine is called like:

Code: [Select]
sub(DD, A, "HELLO", C, 5)
In this example, A is r1, "HELLO" is r2, C is r3, 5 is r4.

I once needed more arguments...

On a side note here is a good example of where Haskellian currying would be put to good use.  Let's say you need 8 arguments.  You can always curry so to get some more parameters.

Code: [Select]
(ADD8(1,2,3,4,5,6))(7,8)

Lbl ADD8
  r1+r2+r3+r4+r5+r6->r6
  λ(r6+r1+r2)
Return

Trivial example again, but shows essentially what I mean.  While this example contradicts it, I suggest you limit curried functions up to 5 parameters so that r6 can hood intermediate values between function followings.
Title: Re: [Tutorial] Edition 2: Using Axe to its full functional form λ
Post by: ztrumpet on July 28, 2011, 09:55:39 pm
So, is this just going to never be in the new "Tutorials" section?  I've asked like 5 times in 3 separate threads, and I'm pretty much forced to give up all hope.  People who want to see this will have to follow the new "this is outdated link" in the old tutorial, I guess :/
Nope, you can add it now. :D

If you'd like, I can add it for you.  Just let me know. :)
Title: Re: [Tutorial] Edition 2: Using Axe to its full functional form λ
Post by: Ashbad on July 28, 2011, 09:57:54 pm
So, is this just going to never be in the new "Tutorials" section?  I've asked like 5 times in 3 separate threads, and I'm pretty much forced to give up all hope.  People who want to see this will have to follow the new "this is outdated link" in the old tutorial, I guess :/
Nope, you can add it now. :D

If you'd like, I can add it for you.  Just let me know. :)

orly?

I didn't know I could add this.. Sorry for the bitching :P
Title: Re: [Tutorial] Edition 2: Using Axe to its full functional form λ
Post by: ztrumpet on July 28, 2011, 10:06:17 pm
So, is this just going to never be in the new "Tutorials" section?  I've asked like 5 times in 3 separate threads, and I'm pretty much forced to give up all hope.  People who want to see this will have to follow the new "this is outdated link" in the old tutorial, I guess :/
Nope, you can add it now. :D

If you'd like, I can add it for you.  Just let me know. :)

orly?

I didn't know I could add this.. Sorry for the bitching :P
It actually just got changed: http://ourl.ca/12282

I didn't know how to do it before, so that's why I never offered until now. ;)
Title: Re: [Tutorial] Edition 2: Using Axe to its full functional form λ
Post by: DJ Omnimaga on July 28, 2011, 10:42:12 pm
Well to be honest after I left the tutorials section kinda got abandonned. No more tutorials got added, but now that they can be added by their respective authors too, this should help a lot speeding up the process.
Title: Re: [Tutorial] Edition 2: Using Axe to its full functional form λ
Post by: WaeV on September 19, 2011, 09:33:20 pm
Hey guys, I was really impressed by these new features of Axe, so I decided to register to make this post!  I figured we could use a non-trivial example of how lambdas can be actually used.


This is an example of some functional code that we wrote in one of my programming classes.  The objective was to write a function that creates iterators.  Each time you call the iterator, it returns one more than the previous call.  We do this with lambda syntax and closures.  We wrote this in Scheme, but I was surprised and impressed to see it correctly execute in Axe.

The Axe code:
(I used liberal amounts of spaces to get it to line up the way I did)
Code: [Select]
.ITERATE

Iter()→L

Disp (L)()►Dec,i
Disp (L)()►Dec,i
Disp (L)()►Dec,i

Iter()→M

Disp (M)()►Dec,i
Disp (M)()►Dec,i
Disp (L)()►Dec,i

Lbl Iter
Return
λ(
  λ(
    λ(
      r₁+1→r₁
    )
  )(0)
)()

Output:
Code: [Select]
asm(prgmITERATE
    1
    2
    3
    1
    2
    4

An interesting side-effect of this is that the current iteration is not stored in any variables - it's captured in the closure.  Not that it's efficient to do this on a calculator with limited memory, but...
Title: Re: [Tutorial] Edition 2: Using Axe to its full functional form λ
Post by: Michael_Lee on September 20, 2011, 09:52:41 pm
That's pretty cool!

You should post that in the Axe Routines Thread (http://ourl.ca/412970)

I don't know much about functional programming -- is it possible to pass in an arbitary lambda to the iterator generator so that it can iterate over a sequence of numbers other then just '1 2 3 4'?

Title: Re: [Tutorial] Edition 2: Using Axe to its full functional form λ
Post by: WaeV on September 21, 2011, 02:11:02 am
Yeah sure!  You can do that. The outer lambda returns the inner lambda - your phrase "iterator generator" is a good one - but it could return any lambda.

Edit: Here's a version which lets you decide where to start.
The Axe code:
Code: [Select]
.ITERATE

Iter(10)→L

Disp (L)()►Dec,i
Disp (L)()►Dec,i
Disp (L)()►Dec,i

Lbl Iter
Return
λ(
  λ(
    λ(
      r₁+1→r₁
    )
  )(r₁)
)()

Output:
Code: [Select]
asm(prgmITERATE
    11
    12
    13
Title: Re: [Tutorial] Edition 2: Using Axe to its full functional form λ
Post by: epic7 on October 23, 2011, 10:08:27 pm
What are the r1, r2, etc.?
Title: Re: [Tutorial] Edition 2: Using Axe to its full functional form λ
Post by: Deep Toaster on October 23, 2011, 11:02:35 pm
Subroutine arguments, as in sub(LBL,1,2,3) calls LBL with 1 in r1, 2 in r2, and 3 in r3.
Title: Re: [Tutorial] Edition 2: Using Axe to its full functional form λ
Post by: Builderboy on October 23, 2011, 11:27:52 pm
Hey guys, I was really impressed by these new features of Axe, so I decided to register to make this post!  I figured we could use a non-trivial example of how lambdas can be actually used.


This is an example of some functional code that we wrote in one of my programming classes.  The objective was to write a function that creates iterators.  Each time you call the iterator, it returns one more than the previous call.  We do this with lambda syntax and closures.  We wrote this in Scheme, but I was surprised and impressed to see it correctly execute in Axe.

The Axe code:
(I used liberal amounts of spaces to get it to line up the way I did)
Code: [Select]
.ITERATE

Iter()→L

Disp (L)()►Dec,i
Disp (L)()►Dec,i
Disp (L)()►Dec,i

Iter()→M

Disp (M)()►Dec,i
Disp (M)()►Dec,i
Disp (L)()►Dec,i

Lbl Iter
Return
λ(
  λ(
    λ(
      r₁+1→r₁
    )
  )(0)
)()

Output:
Code: [Select]
asm(prgmITERATE
    1
    2
    3
    1
    2
    4

An interesting side-effect of this is that the current iteration is not stored in any variables - it's captured in the closure.  Not that it's efficient to do this on a calculator with limited memory, but...

I can't replicate your output?  I get 1,2,3,1,2,3.  I think the issue is that you believe r1-r6 to be local variables to each function, but in fact they are global?
Title: Re: [Tutorial] Edition 2: Using Axe to its full functional form λ
Post by: epic7 on October 24, 2011, 07:46:08 pm
Subroutine arguments, as in sub(LBL,1,2,3) calls LBL with 1 in r1, 2 in r2, and 3 in r3.

What's a subrouine argument?P
Title: Re: [Tutorial] Edition 2: Using Axe to its full functional form λ
Post by: aeTIos on October 25, 2011, 10:52:00 am
a subroutine argument is a value you give to a subroutine.
Title: Re: [Tutorial] Edition 2: Using Axe to its full functional form λ
Post by: LincolnB on October 25, 2011, 06:09:03 pm
Do this:

prgmTEMP

.STUFF

ClrHome

Stuff(1)

Pause 3000
Return

Lbl Stuff
Disp r1>Dec
Return

..end of prgmTEMP

Compile it, run prgmSTUFF, and it will display the letter 1.
Title: Re: [Tutorial] Edition 2: Using Axe to its full functional form λ
Post by: epic7 on October 25, 2011, 06:51:32 pm
a subroutine argument is a value you give to a subroutine.

How would you use a value given to a subroutine?
Title: Re: [Tutorial] Edition 2: Using Axe to its full functional form λ
Post by: Builderboy on October 25, 2011, 07:14:43 pm
epic7, have you read the Axe user guide?  It has a lot of answers to a lot of the questions you have been having :)  To pass an argument to a subroutine, you would type Sub(ARG) where ARG is put into r1 when the routine is called
Title: Re: [Tutorial] Edition 2: Using Axe to its full functional form λ
Post by: epic7 on October 25, 2011, 08:26:46 pm
.... I give up.
Title: Re: [Tutorial] Edition 2: Using Axe to its full functional form λ
Post by: Builderboy on October 25, 2011, 08:48:23 pm
Don't give up!  I know Axe is a little confusing at first, but what specifically is confusing you?
Title: Re: [Tutorial] Edition 2: Using Axe to its full functional form λ
Post by: epic7 on October 25, 2011, 10:25:53 pm
I gave up when people gave me answers, I had more questions. :P

I re-read it again, now I get it.

Also... Why do i get errors every time i try to open zedd?


(later edit)
NOOOOOOOO!!! My ram cleared when I was a few minutes from finishing a game.
Title: Re: [Tutorial] Edition 2: Using Axe to its full functional form λ
Post by: LincolnB on October 25, 2011, 11:34:18 pm
RAM clears. Dude, story of my life. Back up your work - I had to learn the really hard way.
Title: Re: [Tutorial] Edition 2: Using Axe to its full functional form λ
Post by: Hayleia on October 26, 2011, 07:40:48 am
RAM clears. Dude, story of my life. Back up your work - I had to learn the really hard way.
Also, Axe can compile even if the source is archived, so archive it :)
Title: Re: [Tutorial] Edition 2: Using Axe to its full functional form λ
Post by: epic7 on October 26, 2011, 10:26:16 pm
How do you type the lambda sign on the calculator?
Title: Re: [Tutorial] Edition 2: Using Axe to its full functional form λ
Post by: chattahippie on October 26, 2011, 10:34:43 pm
How do you type the lambda sign on the calculator?

press the log button while in editing an axe program :)
Title: Re: [Tutorial] Edition 2: Using Axe to its full functional form λ
Post by: LincolnB on October 30, 2011, 09:08:08 pm
log? I thought it was ln.
Title: Re: [Tutorial] Edition 2: Using Axe to its full functional form λ
Post by: epic7 on October 30, 2011, 09:10:50 pm
Yep, log
Title: Re: [Tutorial] Edition 2: Using Axe to its full functional form λ
Post by: LincolnB on October 30, 2011, 09:35:45 pm
my bad.