Tutorial snippets


#1

For Loops and Such, in Frogatto:
A common question from those familiar with imperative programming languages, is “how can I do a for loop, in FFL”?

You can’t, by design, because FFL is a functional programming language. Instead, there are some other tools that can achieve the same results via a different means. For/while/etc loops are used for a variety of different things, and the best way to know the corresponding thing in frogatto is to ask what you’re trying to accomplish.

Firstly, I should explain frogatto’s map operation, since it’s used by several of these. The basic container class in frogatto is a “list”; which is something like a array in javascript. It differs from arrays/vectors in C in that it can store members of different types in the same list - it can store any of frogatto’s basic types (including but not limited to strings, ints, decimals, and lists - you can have a list of lists). Like arrays in C, members can be accessed with list_name[index] syntax. A helpful value is list.size, which returns how many elements are in a list.

The map operation takes a list, and “does something” to each member; that is, it returns a new list, with all members of the old list passed through the expression you provide. For an example, the expression: map([1,2,3,4], value * 2) is equal to [2,4,6,8]. With this in mind, let’s run through some common uses of for loops:

I’d like to apply something to every member of a list:
The map operation I just described, does that. If you intend to self-overwrite a list, you’d use an expression like: set(mylist, map(mylist, do_something(value)))

I’d like to do something N times:
Frogatto has a useful function called range(int); it makes a new list for you, with members in sequential order. For example, range(5) is equal to [1,2,3,4,5]. The members are in sequence, but they’re also exactly the amount you asked for, so if you just need to do the same thing, say, 5 times, then you can ignore the sequence part and just use this as a shortcut for making a list 5 elements long. So for example, if I have some visual-effect object; say, a sparkle that appears around frogatto, and I want 6 of them to appear simultaneously, randomly positioned (say, he just grabbed a coin or something), I could call the following code inside frogatto:
map(range(6), spawn(‘sparkle’, mid_x + 1d40-20, mid_y + 1d40-20, facing))

I’d like to do something N times, but have what I do depend on N:
This sequential nature of range is really convenient, because you can use the value of the current member, inside a map operation, very much like you’d use a for-loop’s “i” iterator. For example, if I wanted to spawn 5 shots, each spaced 10 pixels apart, vertically, I could use an expression like:
map(range(5), spawn(‘shot’,x, y + 10*value, facing))

Etc, but I need to start/end at something other than 1 or the last element of the list
Remember that frogatto has slice operators [a:b], which only take a limited subset of a list - if you want a range, going up to 10, to start at 3, rather than 1, you could do range(10)[3:]. You can use this to accomplish much of what you’d do with an initial/final value for i in a for loop. Remember that the value you pass into a slice operator need not be a literal constant, it can be an expression instead.

Etc, but I need to do only the even ones (or some other criterion):
The filter operation takes a list, and returns a sub-list consisting of only those items which match a given criterion. For example, this would do something only for even values:
map(filter(range(10), ‘foo’, foo%2=0), do_something(value))

You could also achieve the same end with an if-statement, but filtering is probably more efficient:
map(range(10), if(value%2=0, do_something(value))

todo: explain recursion, and tail recursion, the latter of which I don’t yet know how to do in frogatto. Also explain why for-loops are a bad idea in frogatto, which I’m slightly fuzzy on besides it having to do with avoiding overruns, and errant control flow. I’m also tired at the time of writing this, so … ehhh


#2
Sirp: Jetrel: range(5) -> [0,1,2,3,4] [01:36am] Sirp: Jetrel: you can also do range(5,10) to get [5,6,7,8,9] [01:37am] DDR: Hm, I should do a 'style guide'. [01:38am] DDR: Oh, Sirp -- it'd be nice if the system which prints a level to file could put the small stuff at the top. [01:38am] DDR: for some reason, level id is floating somewhere around the middle of the file. [01:38am] DDR: It's fine if you know exactly what to search for, but it was really quite nice having that sort of stuff at the top. [01:39am] akhiros: seems like it prints things in alphabetal order... [01:39am] DDR: Ah, that's it. Yeah. Let's not do that. [01:40am] DDR: Jetrel: Is it OK if I change list.size to size(list)? [01:41am] DDR: I don't like list.size, it seems inconsistent and size(list) is more commonly used. [01:42am] Sirp: yeah we should deprecate list.size [01:42am] Sirp: size(list) is what should be used. FFL is a functional language

#3

Edit?

For Loops and Such, in Frogatto:
A common question from those familiar with imperative programming languages, is “how can I do a for loop, in FFL”?

You can’t, by design, because FFL is a functional programming language. Instead, there are some other tools that can achieve the same results via a different means. For/while/etc loops are used for a variety of different things, and the best way to know the corresponding thing in frogatto is to ask what you’re trying to accomplish.

Firstly, I should explain frogatto’s map operation, since it’s used by several of these. The basic container class in frogatto is a “list”; which is something like a array in javascript. It differs from arrays/vectors in C in that it can store members of different types in the same list - it can store any of frogatto’s basic types (including but not limited to strings, ints, decimals, and lists - you can have a list of lists). Like arrays in C, members can be accessed with list_name[index] syntax. A helpful function is size(list), which returns how many elements are in a list.

The map operation takes a list, and “does something” to each member; that is, it returns a new list, with all members of the old list passed through the expression you provide. For an example, the expression: map([1,2,3,4], value * 2) is equal to [2,4,6,8]. With this in mind, let’s run through some common uses of for loops:

I’d like to apply something to every member of a list:
The map operation I just described, does that. If you intend to self-overwrite a list, you’d use an expression like: set(mylist, map(mylist, do_something(value)))

I’d like to do something N times:
Frogatto has a useful function called range(int); it makes a new list for you, with members in sequential order. For example, range(5) is equal to [0,1,2,3,4]. The members are in sequence, but they’re also exactly the amount you asked for, so if you just need to do the same thing, say, 5 times, then you can ignore the sequence part and just use this as a shortcut for making a list 5 elements long. So for example, if I have some visual-effect object; say, a sparkle that appears around frogatto, and I want 6 of them to appear simultaneously, randomly positioned (say, he just grabbed a coin or something), I could call the following code inside frogatto:
map(range(6), spawn(‘sparkle’, mid_x + 1d40-20, mid_y + 1d40-20, facing))

range(5,10) is equal to [5,6,7,8,9].

I’d like to do something N times, but have what I do depend on N:
This sequential nature of range is really convenient, because you can use the value of the current member, inside a map operation, very much like you’d use a for-loop’s “i” iterator. For example, if I wanted to spawn 5 shots, each spaced 10 pixels apart, vertically, I could use an expression like:
map(range(5), spawn(‘shot’,x, y + 10*value, facing))

Etc, but I need to do only the even ones (or some other criterion):
The filter operation takes a list, and returns a sub-list consisting of only those items which match a given criterion. For example, this would do something only for even values:
map(filter(range(10), ‘foo’, foo%2=0), do_something(value))

You could also achieve the same end with an if-statement, but filtering is probably more efficient:
map(range(10), if(value%2=0, do_something(value))

todo: explain recursion, and tail recursion, the latter of which I don’t yet know how to do in frogatto. Also explain why for-loops are a bad idea in frogatto, which I’m slightly fuzzy on besides it having to do with avoiding overruns, and errant control flow. I’m also tired at the time of writing this, so … ehhh


#4

How to do basic recursion in Frogatto – just call the function:

def binary_search(haystack, needle)
if(haystack = [], null,
if(needle = haystack[index], haystack[index],
if(needle < haystack[index],
binary_search(haystack[:index], needle),
binary_search(haystack[index+1:], needle)))
where index = size(haystack)/2)

An anonymous function can call itself using recurse.

FFL supports special recursion guards to separate the base and recursive cases:

def linear_search(haystack, needle)
base haystack = []: null
base haystack[0] = needle: haystack[0]
recursive: linear_search(haystack[1:], needle)

When the function is called, it will check each of the ‘guards’ and find the first with an expression that matches. The last guard must always be called recursive, and may not have a condition.

Note that,

[ul][li]The base cases may not make recursive calls.[/li]
[li]The recursive case must make exactly one recursive call. This limitation of exactly one recursive call may be removed in future.[/li][/ul]

Using recursion guards makes recursion much more readable, and also allows FFL to optimize the recursion’s use of the stack, unwinding the recursion and allowing for recursion that goes millions of frames deep.


#5

Equality in FFL is fairly common-sense. Here are some examples:

Lists.

Just as we’d expect.

Maps.

Order doesn’t matter in maps.

Numbers.

Forget anything your comp. sci. teacher said about not comparing decimals with integers. Frogatto doesn’t use floating-point numbers, so everything is nice and sane here. As the last result demonstrates, though, you’ve only got six decimal places to work with. Any additional numbers are dropped. Also:

2147483647 is the largest number in FFL. This also means that you never have to worry about dividing by 0, because all your equations still work!

It’s a computer thing. If you add one to the largest possible number, you get the smallest possible number. However, some computers will clip the number to the largest available number while some will wrap around. When possible, avoid using this behaviour.

Functions:

Functions cannot equal other functions, but they can equal themselves.

Objects:
Objects work like functions.

Anyhow, I think that’s about it. No real surprises there, except for maybe the bit around the largest and smallest number. Happy coding!


#6

FWIW, list equality works exactly as if it were implemented like this:

def lists_equal(a, b) size(a) = size(b) and filter(range(size(a)), a[value] != b[value]) = []

Maps automatically have all their keys sorted after parsing. Map equality could be implemented like this:

def maps_equal(a, b) keys(a) = keys(b) and values(a) = values(b)

Note that all FFL values can also be compared by magnitude, i.e. with <, >, <=, >= operators.