Monday, March 30, 2009
Adventures in Prolog - Link List I
Learn Prolog Now - An online (and paperback) book to learn Prolog
Aspect-Oriented Programming Prolog
Adventures in Prolog - another online book to learn Prolog
P99-Ninety-Nine Prolog Problems - a set of Prolog challenges organized into different degree of difficulty and domains
So happy reading and solving problems :D
Tuesday, March 17, 2009
Adventures in Prolog - computations with Lists V
Today's post presents a predicate defined for lists that is as simple as yesterdays rem_dups/2. flatten/2 is concerned with flattening an arbitrary list to a one-dimensional list/array.The idea behind flatten is pretty simple, i.e. if a list is non-flat we lower its dimensionality by taking theinner of that list and process it further until we reach a one-dimensional list.
%flatten/2
flatten([], []).
flatten([[]], []).
flatten([[HT]], X) :- flatten([HT], X).
flatten([[H]T], X) :- flatten([HT], X).
flatten([H[T]], X) :- flatten([HT], X).
flatten([HT], X) :-
flatten(T, Y),
append([H], Y, X).
Monday, March 16, 2009
Adventures in Prolog - computations with lists IV
rem_dups2([X[]], [X]).
rem_dups2([HT], X) :-
member(H, T),
!,
rem_dups2(T, X);
rem_dups2(T, Y),
append([H], Y, X).
Sunday, March 15, 2009
Adventures in Prolog - Computations with lists III
rem_dups([X[]], [X]).
rem_dups([HT], X) :-
member(H, T),
!,
remove(H, T, Y),
rem_dup([HY], X);
rem_dup(T, Y),
append([H], Y, X).
The problem forumulation basically says that if the head of a list is contained within the tail of the list it is a duplicate. Consequently, this duplicate (and any further duplicate of H) is removed from T. Since we want to retain H, we need to connect it with the list that does not contain any instance of H, i.e. X. This procedure is followed for all elements of the list. If a list element does not have a duplicate it is not removed from the list.
rem_dup makes use of auxiliary predicates like remove/3, append/3 and member/2. member/2 checks whether some X is element of some list L. remove/3 removes some X from list L1 yielding the result list L2. append/3 does the opposite it appends some X to an existing list L1 yielding L2.
Thursday, March 05, 2009
Adventures in Prolog - Link
If you follow this link you will be taken to "The First 10 Prolog Programming Contests". So indulge some brain food.
Wednesday, February 25, 2009
Adventures in Prolog - Simplify Sum (2)
addition_expression(A) :- sum_term(A).
addition_expression(A) :-
A = X + Y,
addition_expression(X),
sum_term(Y).
sum_term(X) :- number(X).
sum_term(X) :- atom(X).
sum_term(X) :- prod_term(X).
prod_term(X) :- X = A * B, number(A), atom(B).
prod_term(X) :- X = A * B, atom(A), number(B).
Sunday, February 22, 2009
Adventures in Prolog - Simplify Sum (1)
For example, Prolog offers the following (and more) built-in predicates:
- number/1 - is the argumet passed, a number, e.g. number(1) returns true
- atom/1 - is the passed argument an atom, e.g. atom(x) returns true
- compound/1 - is the passed argument a compound term, e.g. compound(X+Y) returns true
Now, that we know how to inspect the type of some Prolog symbol, we may take a look onto today's task. Given some summation, the task is to simplify this summation, using some predicate called simplify_sum or simp_sum (for short).
For example:
- 1 +2 +3 = 6
- 1 +a = a +1
- a + b + 1 + c = a+ b +c + 1
- a + 1 +2 + b = a + b + 3
So in short, the summation should be ordered with atoms first and aggregated numbers last. The original task by Bratko is concerned with the aggration of atoms as well, such as x +x = 2*x, but I will keep this for the next post.
So based on the above statement of the problem, we must consider some elementary cases, such as:
- number + atom = atom + number
- number + number = number
- atom1 + atom2 = atom1 + atom2
- atom + number = atom + number
These cases will act as the recursion anchor in our simp_sum clauses. Based on this reduction to the simplest form of the problem (please note, that we do not consider a case where only one atom or one number is passed to simp_sum), we identify more advanced incarnations of the problem.
We must consider the following:
- some compound term + number
- some compound term + atom
cases as well. The reason for compound term occuring only on the left-hand side is the associativity of the + operator. For example. 3 + 4 + 5 is (3 + 4) + 5 and consuequently we have 3+ 4 +5 = compound + number where compound = number + number.
Putting together all this information we might come up with the following ...
simp_sum(X + Y, R) :- number(X), number(Y), R is X + Y.
simp_sum(X + Y, X + Y) :- atom(X), number(Y).
simp_sum(X + Y, Y + X) :- atom(Y), number(X).
simp_sum(X + Y, X + Y) :- atom(X), atom(Y), X \== Y.
%Result of simpsum is not compound
simp_sum(X + Y, Z) :-
simp_sum(X, X0), number(X0), number(Y), Z is X0 + Y.
simp_sum(X + Y, Y + X0) :-
simp_sum(X, X0), number(X0), atom(Y).
%Result of simpsum is compound
simp_sum(X + Y, A + Y0) :-
simp_sum(X, X0), number(Y), X0 = A + B,
number(B), simp_sum(B+Y, Y0).
simp_sum(X + Y, A + B + Y) :-
simp_sum(X, X0), number(Y), X0 = A + B, atom(B).
simp_sum(X + Y, A + Y + B) :-
simp_sum(X, X0), atom(Y), X0 = A + B, number(B).
simp_sum(X + Y, A + B + Y) :-
simp_sum(X, X0), atom(Y), X0 = A + B, atom(B).
When Prolog is asked:
simp_sum(1 + b + 2 + c + a + 4 + d + 39 + e+ f + 122, X).
It answers correctly:
X = b+c+a+d+e+f+168 .
Thursday, February 19, 2009
Adventures in Prolog - Computations with lists II
At first we define the processList function. processList takes 4 input parameters - a list, a processing function some identity element and the result. processList processes some input list according to the provided processing function. The identity Identity element is used to process the empty list. The result of this operation is placed into the variable Res.
%processList/4
processList([], F, Identity, Identity) :- functor(_, F, 3).
processList([HT], F, Identity, Res) :-
functor(_, F, 2),
processList(T, F, Identity, L1),
apply(F, [H, L1, Res]).
The functor procedure checks whether the user supplied processing function F is indeed a function accepting 3 Variables (F/3). processList is similar to mulList or addList, in that it uses the recursive definition of a list to process each list element. apply is used to call the user-supplied procedure F with submitted input variables.
By itself processList does not do much, it is merely the skeleton to enable abstract computation on lists. To make use of it, we have to define some processing function F.
As mentioned, I want to use processList to abstract addList and mulList. For this, let's define two ternary relations add and mul. add is used to realize addList and mul is given to realize mulList. Their definition is straightforward and presented in the following.
%test ops
add(X, 0, X).
add(0, _, 0).
add(X, Y, Z) :- Z is X + Y.
mul(_, 0, 0).
mul(0, _, 0).
mul(X, 1, X).
mul(1, X, X).
mul(X, Y, Z) :- Z is X*Y.
Given the above definitions, we may ask Prolog now:
?- processList([1, 2, 3, 4, 5], add, 0, R).
, which yields:
R = 15
Clearly, add and mul are simple examples but more powerful processing functions can be implemented and passed to processList.
Wednesday, February 18, 2009
Adventures in Prolog - Computations with lists
A list in Prolog is a recursive data structure itself. Why? Because a list can be built by remembering the following ...
1. the empty list [] is a list
2. a list can be built by appending any list T to an item H, which yields [HT]
Using this definition we can see that the list [1, 2, 3, 4] is indeed a list with H = 1 and T = [2, 3, 4]. Consequently, a list cannot only be built from points 1. and 2. but also decomposed according to 1. and 2. Therefore 1. and 2. form the underlying principle when computing with lists in Prolog.
Now that we have covered the basic principle underlying a list. I will present two operations on lists - the addition of elements of a list (sumList) and the multiplication of elements of a list (mulList).
Both operations make use of the presented recursive structure of a list. The needed recursion anchor is the processing of the empty list. This maps to the identity operation in addition and multiplication. Identity in addition is performed using the zero element thus - a + 0 = 0 + a = a. Identity in multiplication is done by multiplying with the one element thus a * 1 = 1 * a = a.
Employing both identities, the definition of sumList and mulList become straightforward. A list is peeled down until it is stripped to the empty list, in this case the identity operation is performed. While peeling the list each element is either added or multiplied with the result obtained by performing the operation on the remaining unpeeled list (the list's tail T).
%sumList/2 sum list elements%
sumList([], 0).
sumList([HT], L) :-
sumList(T, L1),
L is H + L1.
%mul list elements%
mulList([], 1).
mulList([HT], L) :-
mulList(T, L1),
L is H * L1.
In my next post, I will cover the abstraction from special computations on lists to defining a general operation on a list, which executes a special function on each list item. This is similar to F#'s list-map function.
Sunday, February 15, 2009
Adventures in Prolog - Simple computations
Power is implemented as a simple ternary relation, which uses recursion. The base cases for power are of course the 0th and 1st power of some integer number. All other powers will be dependant on this anchor. The ith power of j means that j is multiplied with itself i times. For instance, the 3rd power of 2 is eigth, which is 2 * 2 * 2 = 8. This is used to implement the recursive core of power, which is ith power of j is the j * (i-1)th power of j.
After the basic power relation, power10 and power2 show how to use existing relations to implement some simple abstractions.
%power/3
power(X, 0, 1).
power(X, 1, X).
power(X, Y, Z) :-
Y1 is Y - 1,
power(X, Y1, Z1),
Z is X * Z1.
%power10/2
power10(P, R) :- power(10, P, R).
%power2/2
power2(P, R) :- power(2, P, R).
Adventures in Prolog - Fibonacci
:- dynamic(fib/2).
fib(0, 1).
fib(1, 1).
fib(F, X) :-
F1 is F-1,
F2 is F-2,
fib(F1, X1),
fib(F2, X2),
X is X1 + X2,
asserta(fib(F, X)).
So what does this listing do? Clearly, it computes the ith value of the Fibonacci sequence using recoursion. Therefore, the recoursion anchor - 1st and 0th value - of the sequence is established first. After that the definition of the sequence is given in its known form.
By making the predicate fib/2 dynamic, we can add facts to the list of clauses covering fib/2. Dynamic has to be executed upon loading the fib database. That is why we write :- dynamic(fib/2). .
Now new knowledge about the Fibonnaci values can be added to the database. This is what is done later one with the asserta statement - asserta adds new clauses at the beginning of the database (assertz at the end). The value of the computation of the jth Fibonacci sequence value (fib(J, X)) is added as a fact to the database, thereby speeding up future computations of the same Fibonacci sequence value.
Saturday, August 23, 2008
Adventures in F# - A port of the simplest Herbivore
So here comes the code ...
namespace
CBHerbivore
#light
#r "E:\\Development\\my fsharp\\Terrarium\\Terrarium\\OrganismBase.dll"
open System;;
open System.Drawing;;
open System.Collections;;
open System.IO;;
open OrganismBase;;
//Sample Herbivore
//The following Assembly attributes must be applied to each
//Organism Assembly
[<assembly: OrganismClass("CBHerbivore.CBHerbivore")>]
//The class that derives from Animal
[<assembly: AuthorInformation("Christian Bitter", "x@y.z")>]
//It's an herbivore
[<CarnivoreAttribute(false)>]
//This value must be between 24 and 48, 24 means faster
//reproduction
//while 48 would give more defense and attack power
//Make it smaller for reproduction
[<MatureSize(26)>]
//AnimalSkin = AnimalSkinFamilyEnum.Beetle, you can be a Beetle
//an Ant, a Scorpion, an Inchworm, or a Spider
//MarkingColor = KnownColor.Red, you can choose to mark your
//creature with a color.
//This does not affect appearance in the game.
[<AnimalSkin(AnimalSkinFamily.Beetle)>]
[<MarkingColor(KnownColor.Red)>]
//You get 100 points to distribute among these attributes to define
//what your organism can do.
//Choose them based on the strategy your organism will use.
//This organism hides and has good eyesight to find plants.
[<MaximumEnergyPoints(0)>]
//Don't need to increase this as it just sits next to plants
[<EatingSpeedPoints(0)>] //Ditto
[<AttackDamagePoints(0)>] //Doesn't ever attack
[<DefendDamagePoints(0)>]
//This attribute changes the skin of our herbivore,
//which is now going to be a beetle.
//Point Based Attributes
//Doesn't even defend
[<MaximumSpeedPoints(0)>] //Doesn't need to move quickly
[<CamouflagePoints(50)>] //Try to remain hidden
[<EyesightPoints(50)>] //Need this to find plants better
type CBHerbivore () =
inherit Animal()
override sh.Initialize() = ()
override sh.SerializeAnimal (m:MemoryStream) = ()
override sh.DeserializeAnimal (m:MemoryStream) = ()As you may see, the main difference between this herbivore and the previous plant, is the base type our herbivore type needs to implement, and some attributes declared on our animal. In this case the abstract Animal class, declares 3 abstract members (Initialize, SerializeAnimal, DesirializeAnimal), which need to be implemented by our herbivor. Attributes control some of the properties of our herbivore, such as its moving speed, etc.
Again, if you compile this type and introduce it to your terrarium, do not be surprised, to see, that the animal is stiff and not moving like an animal during hibernation. This is due to not implemented event handlers. These event handlers are responsible for your animal's interaction with its environment.
Adventures in F# - A Plant for Terrarium 2
Recently, my beloved Terrarium-game has reappeared from the neatherworlds of software. As some of you may know, Terrarium's intend was to showcase the back then rather new and exciting .NET platform version 1.x (not that it is not still exciting). Although from a gamer's perspective, the graphics weren't all to great, from a technology standpoint, it featured great things, such as Webservices, Reflection, etc.
At some point Terrarium ceased to exist, which was a shame, since the community was quite active developing plants, herbivores and carnivores for the virtual ecosystem that Terrarium simulates. I for myself, developed some simple creatures too (a simple decision-based/state-based agent), as part of a project I did during university for my AI course. More advanced (in comparison to my creature) could be imported showcasing great AI stuff such as A*, neural networks, planning, etc.
However, in an community effort, Terrarium was relaunched lately on codeplex and will hopefully see great new additions, such as a port to a more current version of the .NET platform and DirectX.
In a small attempt I tried to put my superficial F# skills to work, and decided to port a plant organism to F#. My attempt can be seen in the following lines of code. For a C# version, see the codeplex discussion here. I decided to leave the comments from the discussion as is.
namespace CBPlant
We open a namespace for the plant organism
#light
#r "E:\\Path to OrganismBase.dll\\OrganismBase.dll"
We set the environment to lightweight and reference the OrganismBase.dll, which contains all the Terrarium2 stuff.
open System;;
open System.Drawing;;
open System.Collections;;
open System.IO;;
open OrganismBase;;
We open some namespaces, which we are going to use later and dive right into the code.
// Sample Herbivore
//Strategy//This animal moves until it finds a food source and
//then stays there
// The following Assembly attributes must be applied to each
//Organism Assembly
[<assembly: OrganismClass("CBPlant.CBPlant")>] // The class that derives from Animal
[<assembly: AuthorInformation("XYZ", "x@y.z")>] // Provide Author Information
do()
Assembly-level attributes have to be declared via a global do() statement. See the discussion here.
//3.2 Plants
//The definition of a plant is relatively easy since plants do not have to have any sort of movement defined to allow them to locate sources of food.
//Each plant has three basic functions:
//1. Grow
//2. Reproduce by spreading seeds
//3. Be eaten by herbivores
//A plant organism does not need to contain any methods, it just has three properties that define how a plant functions.
//4
//1. The “MaximumEnergyPoints” property allows the developer to state how many energy points a herbivore will gain by consuming this plant. The maximum allowed is 10.
//2. The “MatureSize” property which must be a number between 24 and 48 states the maximum size a plant can grow to when it has survived for some amount of time without being consumed. The smaller a plant is, the faster it will be able to reproduce. As a plant gets larger it will become easier for herbivores to see and will more likely be consumed.
//3. The “SeedSpreadDistanceAttribute” states the maximum distance a plant can spread seeds from its current location. The maximum allowed is 100. These three properties alone are enough to define a functioning plant for the Terrarium game.
// This value must be between 26 and 48, 26 means faster reproduction
// while 48 would give more defense and attack power
// Make it smaller for reproduction*)
[<MatureSize(26)>]
[<SeedSpreadDistance(100)>]
// Point Based Attributes
// You get 100 points to distribute among these attributes to define
// what your organism can do.Choose them based on the strategy your organism
// will use. This organism hides and has good eyesight to find plants
[<MaximumEnergyPoints(10)>]
type CBPlant () =
inherit Plant ()
override cb.SerializePlant (m:MemoryStream) = ()
override cb.DeserializePlant (m:MemoryStream) = ()
;;
We define a new plant type, called CBPlant (full CBPlant.CBPlant). This type is a subclass of the abstract class Plant. We have to implement Plant's two abstract members, which according to the example is just an empty method body. If we compile this by invoking
fsc OrganismBase.dll CBPlant.fs -a
A new library will be created, containing just this simple type.
Hopefully, I will get to play some more with F# and Terrarium doing some other stuff, like porting the Herbivore, Carnivore and start to add some real behaviour.
Adventures in F# - F# and ADO.NET
Today's post is rather simplistic in what it does, but it illustrates some key language elements of F#, such as exception handling.
The task to accomplish is quite it easy, nameley, to connect to a SQL Server 2005 database called "TestDB" on my local machine, using ADO.NET to pull out some rows of the "Person" table having the following schema:
Person (
PersonID: int;
FirstName nvarchar(50);
LastName nvarchar (50);
Street nvarchar(50);
City nvarchar(50);
ZIP int
)
The code we use in F# is a rather straightforward conversion of some typical C# code, and as such is probably not the best way to do things, but it gets the task done, and may illustate the point.
#light
We use the lightweight syntax option.
open System.Data;
open System;
open System.Data.SqlClient;
As a next step, we have to open the correct namespaces.
let ADONetTest =
let conStringBuilder = new SqlConnectionStringBuilder()
conStringBuilder.IntegratedSecurity <- true
conStringBuilder.["Data Source"] <- "localhost"
conStringBuilder.InitialCatalog <- "TestDB"
let con = new SqlConnection(conStringBuilder.ConnectionString)
These lines create the connection to the SQL Server 2005 database "TestDB" on my local machine. As you may see I use a mixture of passing values to properties (IntegratedSecurity, InitialCatalog) and the indexer (["Data Source"]) that is defined on the SqlConnectionStringBuilder type.
try
con.Open()
let cmdString = "SELECT * FROM [dbo].[Person]"
let cmd = new SqlCommand(cmdString, con)
cmd.CommandType <- CommandType.Text
using (cmd.ExecuteReader()) (fun reader ->
if (reader.HasRows) then
(
printfn "Queried: %s" cmdString
while (reader.Read()) do
(
let id = reader.GetInt32(0)
let firstName = reader.GetString(1)
let lastName = reader.GetString(2)
let street = reader.GetString(3)
let city = reader.GetString(4)
let zip = reader.GetInt32(5)
printfn "%d %s %s %s %s %d" id firstName lastName street city zip
)
done
)
else (printfn "Empty result")
)
con.Close()
with
| :? System.Data.SqlClient.SqlException as sqlEx -> printfn "%A" sqlEx.Message
| _ -> printfn "Unknown Exception"
(con :> IDisposable).Dispose ()
;;
This part is responsible for the main functionality. We open the previously specified connection. We do this in a try-with block, to be prepared in case of exceptions. We actually try to handle one exceptio, the SqlExceptio. In the with block, we use type/pattern matching rule (|:? SqlException) to catch this particular exception. Since we do not have a handling strategy in place, a printf command is issued.The next with rule gets executed on whatever type not matching SqlException. We indicate that we do not even care about what it is (| _) using an anonymous rule.
Inside our try block, we declare a SqlCommand and pass in the Sql query stored in the cmdString. variable. This command encapsulates a Select-From-Where SQL-query. We execute the query, using one of F#'s equivalent's of the C# using statement - the using statement (the other one would be use).
The using keeps track for us, that in the case of an exception the "Dispose" method of the object used in the using statement is called - in this case it would be the Dispose declared by the result of SqlCommand.ExecuteReader() - a DataReader object.
Inside the using block, it is asked whether the result of the query (DataReader) actually has rows that were returned by our particular query. This is done by if (reader.HasRows) then () else ().In case rows were returned by that query,they are enumerated by the while do () done loop. This loop does nothing but print each row present in the DataReader.
The last statement to mention is the (con :> IDisposable).Dispose (). This statement casts the connection object into the IDisposable and calls the Dispose method on it. This has to be done, since it is not automatically called by a try-with block, and we have to ensure that all used objects are properly disposed of - espacially those that abstract native resources, such as database or file connections.
Wednesday, August 20, 2008
Small one - SourceSafe via command line
Today I show a little snippet that let's you load some project ("XYZ") from SourceSafe into a specific folder (<Target Directory>). This may come in handy in some sort of automatic build invironment.
At first you need to define, i.e. set as environment variables:
1. SourceSafe User Account, supplied with sufficient privileges to actually access the project you want to retrieve
2. The account's password
3. The path to the SourceSafe DB's SourceSafe configuration file (srcsafe.ini)
Next you ask SourceSafe to change the working directory for the project, you are going to load. You do this via "ss Workfold".
The last step is to load/get the actual project into the working directory.
SET SSUSER=<your SourceSafe Account>
SET SSPWD=<your SourceSafe Account's Password>
SET SSDIR=<the path to your SourceSafe DB>
"SOURCESAFEDIR\ss.exe" Workfold $/<Path to XYZ>/XYZ "<Target Directory>"
"SOURCESAFEDIR\ss.exe" get $/<Path to XYZ>/XYZ -R
The only problem with this solution is, that SourceSafe is going to ask you, whether the intended working folder is the correct one. To fix this we include a change of the current directory into the <Target Directory> and everything will be fine.
SET SSUSER=<your SourceSafe Account>
SET SSPWD=<your SourceSafe Account's Password>
SET SSDIR=<the path to your SourceSafe DB>
cd "<Target Directory>"
"SOURCESAFEDIR\ss.exe" Workfold $/<Path to XYZ>/XYZ "<Target Directory>"
"SOURCESAFEDIR\ss.exe" get $/<Path to XYZ>/XYZ -R
Another way to accomplish this sort of automatic build environment is by the use of SourceSafe initialization variables. These let one configure the SourceSafe environment. By specifying a custom SourceSafe initialization file, one may configure all aspects to one's needs.
Friday, May 02, 2008
Aventures in F# - Fibs
I will present a recursive and an iterative F# approach to generating the sequence.
The Fibbonaci number n = Fib(n) is generated as follows:
Fib(n) = Fib(n-2) + Fib(n-1) where Fib(0) = 0 and Fib(1) = 1
The condition Fib(0) and Fib(1) are the anchor to end the recursion and otherwise it is dug into the recursion. Consequently, ...
1. Recursive Approach
let rec FibRec n =
if n = 0 then 0
else if n = 1 then 1
else (FibRec (n-2) + FibRec(n-1))
;;
As you can see the function is rather straightforward and follows the definition closely. However, its recursive nature make it rather unsuiting for large values of n - you will notice that for large values of n the recursion slows the process down.
2. Iterative approach
let FibIt n =
if n = 0 then 0
else if n = 1 then 1
else
let fibA = Array.create (n+1) 0
fibA.[0] <- 0 fibA.[1] <- 1 for i = 2 to n do
fibA.[i] <- fibA.[i-2] + fibA.[i-1] fibA.[n] ;;
As you can see the iterative approach employs Fib(0) and Fib(1) equally as anchors. However, it uses a for loop starting at two to fill an array at index i with the Fibbonaci number Fib(i). Clearly, we do not need the array but it will come in handy at a later stage.
Although being faster, i.e. compare the recursive approach with the iterative approach for Fib(40) and you will notice some time difference, both approaches suffer data overflow. This means that Fib(48) displays correctly but Fib(49) wraps around the integer boarder and becomes a negative number. Therefore we have to find a way around this problem - probably the next time.
I have come around some valuable resources with respect to F#
Marius Bancila's Blog: http://mariusbancila.ro/blog/
Robert Pickering's Strange Blog: http://strangelights.com/blog/
Tuesday, April 29, 2008
Aventures in F# - words is all you need
For example: Assume we have a list of numbers and want to transform them in a certain way, e.g. we want to square them.
1. generate a list of numbers
let numbers = [for i in 1..10 -> i];;
Now we have different options to reach our goal, i.e. transforming the elements of the list to be equal to their respective square, i.e. i -> i * i
The first way to do this is to generate the set with squared numbers.
let sqnumbers = [for i in 1..10 -> i * i];;
While it solves the problem, it was not exactly what I was looking for.
So we define a function that takes an integer list as input and generates the appropriate output list by taking each element squaring it and appending it to the output list.
Let sqfunc be this function.
One way of calling sqfunc is: sqfunc numbers;;
But we could also use F#'s incredible pipelining operator >
which would result in: numbers > sqfunc;;
The operator matches perfectly the way of reading it, i.e. "put numbers into the pipeline component sqfunc" - Nice
So If we were to compute the fourth power of our numbers list we could write:
numbers > xfunc > xfunc;;
The pipeline operator is nothing but syntatctic suggar, being defined as:
let (>) x f = f x
where x is the input to apply the function f on.
Since we work on lists, we may also use the map function defined on list types. The map function takes as input a function that transforms elements of an input list. Therefore we may write
List.map (fun x -> x * x) numbers;;
This exhibits F#'s anonymous function values - so much like a C# delegate type as an input parameter to a function List.map.
Thursday, April 24, 2008
Adventures in F#
let rec ReverseList (l: int list) =
match l with
¦ H::T -> (ReverseList T) @ [H]
¦ [] -> []
The code is quite simple. It does the following:
- define a recoursive function (rec keyword) on integer list argument
- use pattern matching (match with) on the argument l to decompose l into a head and a tail. The head is the head (first) element of l and tail is the remainder of l.
- use this knowledge to call itself recoursively
- It is checked whether l consists of a head H and a tail T, if yes, then ReverseList calls itself with T (the list consisting of the tail of l, i.e. l without the head element) and concatenates (@ operator) the result with the list consisting of the headelement ([H])
- if the input argument l is the empty list ([]), then ReverseList exits by returning the empty list.
Thursday, December 06, 2007
3D Engine Design
Following is the "table of contents" of the Lightfeather 3D engine design:
Wednesday, November 28, 2007
Talk like an animal, walk like an animal ...
The new download link on windowsclient.net is this one https://windowsclient.net/downloads/folders/starterkits/entry1269.aspx
Browsing through MSDN has surfaced that Tom Anderson did a VB.NET port of Terrarium from .NET framework version 1.x to 2.0. You will find the respective MSDN post here
http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=373738&SiteID=1
Unfortunately, he has stopped working on the project and there is no visible link to me where one can grab the .NET 2.0 port of Terrarium.
Maybe there is some time left to play around a bit ...