Monday, June 15, 2009
Retrospect
I mentioned earlier that the statistical analysis portion of my generator counts the number of syllables in its input set in order to use that data to make certain syllables appear more often than others. While looking through my C# code, it appears that this is not the case - I, in fact, am not using that data for anything.
It was my original intention to use it as such, but in retrospect I recall having issues translating this requirement into functionality - especially since I was using SQL Server to perform my random picking. I wonder if I can fulfill this requirement now that I'm using F# and eschewing SQL.
By the way - when I'm done with this project, I'll post up snippets of my F# for review... I'm sure you vets will have plenty to chuckle at! :)
Saturday, June 13, 2009
F# progress
My next task is to continue the statistical analysis portion, and generate syllable boundary data (which is important for the generator to know how to put words together in ways that make sense). After that, the generator itself needs to be written, which should be a simple matter.
The only question at this point that I have is how to handle the SQL database access - much of the logic for generation is embedded in the SQL calls to the database. I'm considering eschewing the database completely and designing my own file-based storage solution, but then I have a whole new class of problems.
In the end, this is going to get compiled as a class library, for consumption in my name generator website (which currently isn't online).
New F# project
I had forgotten that, apart from simple expression parsers, I used my Random Name Generator project to learn new languages. My name generator requires text input in order to build statistical data from which random words are generated. It was originally written in Visual Basic 6.0, and was ported to VB.NET, then to C#, in order for me to learn those respective languages. I think it's time to do it again. =)
Saturday, October 25, 2008
F# mindblow... simple math expression evaluator
One of the little tasks I typically force upon myself is a simple infix expression evaluator. For the uninitiated, 'infix notation' is the form of notation we humans commonly write our mathematical expression in - that is, the form "a + b * c" etc. Here's a wiki!
Anywho - I decided today was the time for F# to get its own infix evaluator...
Feel free to laugh. I'm laughing at myself, actually - way down inside, in the tiny places, where I harbor my self-loathing and self-doubt, down where I quietly plot my own demise... *ahem*
It took me about 7 hours today to write a total of 95 lines of code. That's ~13 lines of code an hour. Horrible, horrible. Though I'm really not beating myself up as badly as you might think - it took me as long to write this evaluator in VB.NET when I was learning that language (though not nearly as long in C# due to the syntax being the only difference between the languages). I'm just not used to thinking recursively. Sure, I've done recursion in C#, VB.NET, etc., but I've never really used it to replace what would otherwise be imperative-style constructs before. I've only used it when something *had* to be recursive. Also I wanted to adhere to the pure functional programming dogma - zero side effects. This code does indeed adhere to this self-imposed mandate.
Before I post the code, I want to stress that this is *not* optimal code. I know a little about tail recursion, etc., but I *clearly* didn't use it here. I don't even know if I *can* use it here. Also I'm not terribly knowledgeable about the various Seq and List functions that are available, so I probably flubbed them up as well. I don't really care - this works, and I'm proud of it. This is my first major attempt at writing something of any facility in a functional programming language. Also I'd like to mention that I am *very* open to suggestions. If I did something really, truly stupid in here, please call me on it. This is a learning exercise, and I'd like to learn as much as I can from it - part of that is peer review.
So, without further ado, here it is. (Apologies for the different theme - I'm doing this at home and haven't gotten around to installing the darker theme yet.)
1 #light
2
3 open System
4
5 type operator =
6 | Add
7 | Subtract
8 | Multiply
9 | Divide
10
11 type token =
12 | Number of int
13 | OpenParen
14 | CloseParen
15 | Operator of operator
16
17 let tokenize i =
18 let rec tk s =
19 match s with
20 | ' ' :: tail -> tk tail
21 | '(' :: tail -> OpenParen :: tk tail
22 | ')' :: tail -> CloseParen :: tk tail
23 | '+' :: tail -> Operator Add :: tk tail
24 | '-' :: tail -> Operator Subtract :: tk tail
25 | '*' :: tail -> Operator Multiply :: tk tail
26 | '/' :: tail -> Operator Divide :: tk tail
27 | n :: tail when Char.IsNumber(n) ->
28 let rec intListToValue (i:int list) acc c =
29 match i with
30 | [] -> acc
31 | n :: tail -> intListToValue tail (acc + (n * int (10.0 ** float c))) (c + 1)
32 let rec tc (i:int list) (n:char) (s:char list) =
33 let value = Int32.Parse(string n)
34 match s with
35 | n :: tail when Char.IsNumber(n) -> tc (value::i) n tail
36 | x :: tail -> (Number (intListToValue i value 1)) :: tk (x :: tail)
37 | [] -> [Number (intListToValue i value 1)]
38 tc [] n tail
39
40 | [] -> []
41 | n :: _ -> failwith ("Parse error - invalid character detected: " + n.ToString())
42 tk (Seq.to_list i)
43
44 let evalTokens input =
45 let pop2 (stack:'a list) = (stack.Head, stack.Tail.Head, stack.Tail.Tail)
46
47 let eval a b op =
48 match op with
49 | Operator Add -> b + a
50 | Operator Subtract -> b - a
51 | Operator Multiply -> b * a
52 | Operator Divide -> b / a
53 | _ -> failwith "error parsing input"
54
55 let rec eval_rec input numstack (opstack:token list) =
56 match input with
57 | Number n :: tail -> eval_rec tail (n::numstack) opstack
58
59 | Operator op :: tail ->
60 if opstack.Length <> 0 && opstack.Head > (Operator op) then
61 let firstNum, secondNum, numstackRem = pop2 numstack
62 let e = eval firstNum secondNum opstack.Head
63 eval_rec tail (e::numstackRem) (Operator op::opstack.Tail)
64 else
65 eval_rec tail numstack (Operator op::opstack)
66
67 | OpenParen :: tail -> eval_rec tail numstack (OpenParen::opstack)
68
69 | CloseParen :: tail ->
70 match opstack with
71 | Operator op :: opsTail ->
72 let firstNum, secondNum, numstackRem = pop2 numstack
73 let e = eval firstNum secondNum (Operator op)
74 eval_rec input (e::numstackRem) opsTail
75 | OpenParen :: _ ->
76 eval_rec tail numstack opstack.Tail
77 | _ -> failwith "error parsing input"
78
79 | [] ->
80 match opstack with
81 | Operator op :: tail ->
82 let firstNum, secondNum, numstackRem = pop2 numstack
83 let e = eval firstNum secondNum (Operator op)
84 eval_rec [] (e::numstackRem) tail
85 | [] -> numstack.Head
86 | _ -> failwith "error parsing input"
87
88 eval_rec input [] []
You call this like so: evaluate "((1 + 2) * 3) / 3" -- this would, of course, evaluate to 3, as expected - it understands and follows the correct order of operations, and respects parenthesis correctly as expected. It doesn't yet handle floats, but I might get around to that at some point. It'll complicate the parsing, but that's not really that big of a deal. The way I'm handling it is weird anyway...
Well there you have it. My first real F# program of any value at all. Despite taking me 7 hours, I'm rather proud of this. It's taught me a great deal, especially that I need to be patient with myself while trying to learn to think in functions. Also, staying pure and functional can be *hard*, especially coming from an imperative / mutable state world. I should also note that my first C# implementation included around 4 times the number of lines of code...
All told, I really enjoyed my dive into F#. My advice to anyone looking into it as a real programming language (and not as a toy) would be to keep an open mind and give it a fair shot.
Friday, October 17, 2008
square root function update and code coloring
Second, thanks to Guy Burstein for the new code syntax highlighting add-in I'm using for the blog. I was using a javascript syntax colorer, but it wasn't working correctly in RSS readers, and it was clunky to use. This new add-in I'm using allows me to copy my source as HTML, preserving the colors as seen in Visual Studio and allowing me to stick with my darker colorings - I'd have had to mess with CSS to get the old javascript colorer to match my settings, and I just didn't have the patience. Also this works properly with C#, F#, XML, HTML - anything VS displays and colorizes. You see it exactly as I see it. =)
Here's a little code sample to demonstrate. This is a little F# function showing off units of measure to calculate the speed at which a body will hit the Earth from a given height in meters, assuming the Earth has no atmosphere... Not terribly useful perhaps but here it is:
1 #light
2
3 open System
4
5 let out p = Console.WriteLine(p:string)
6 let inp = Console.ReadLine
7
8 let prompt p = out p; inp()
9
10 [<Measure>] type meter
11 [<Measure>] type feet
12 [<Measure>] type mile
13 [<Measure>] type second
14 [<Measure>] type hour
15
16 let gAcc = 9.2<meter/second^2>
17 let feetPerMeter = 3.28084<feet/meter>
18 let secondPerHour = 3600.0<second/hour>
19 let feetPerMile = 5280.0<feet/mile>
20
21 let _ =
22 let i = prompt "Enter a value"
23 let v = ((float i) * 1.0<feet> / feetPerMeter)
24 let spd = sqrt (2.0 * gAcc * v)
25 let spdMpH = ((spd * feetPerMeter) * secondPerHour) / feetPerMile
26 out ("from " ^ (string (Math.Round(float v, 4))) ^ " meters: ")
27 out (string (Math.Round(float spd, 4)) ^ " meters/second")
28 out (string (Math.Round(float spdMpH, 4)) ^ " miles/hour")
29 ignore(prompt "Press enter to end")
So, enjoy!
Friday, October 10, 2008
F# square root approximation function
The idea is simple - starting with your number, and a guess at the square root of the number, iteratively refine the guess using simple arithmetic until you've decided that your guess is close enough.
Here's my implementation, in C#:
1 static decimal mySqrt(decimal number, int iterations) {
2 Func<decimal, int, decimal> rec = null; rec = (guess, iter) =>
3 {
4 if (iter == 0) return guess;
5 return rec((guess + (number / guess)) / 2, iter - 1);
6 };
7
8 return rec(number / 2, iterations);
9 }
This implementation uses a recursive lambda function. I could have stuck with a for-loop which would have been more efficient in C#, but my ultimate goal was to use this problem to help me understand F# better. Here's the same function in F#:
1 #light
2
3 let fsqrt n i =
4 let rec guess g i =
5 match i with
6 | 0 -> g
7 | _ -> guess ((g + (n / g)) / 2M) (i - 1)
8 guess (n / 2M) i;;
In both of these functions I'm allowing the caller to specify how many refining iterations to perform. I'm considering writing a method that will determine the fitness of a guess.
I'd like to compare this solution against the official .NET implementation of Math.Sqrt, but unfortunately that function is a stub - it's implemented in MSVCRT by calling the 'fsqrt' opcode, as answered in my StackOverflow question on the subject. If anyone has any more insight into how this works on the processor, please post an answer there - I *really* want to know how it works...
Thursday, October 9, 2008
F#, C#, and games programming
I'll go into details when I have something concrete to show - but for now, suffice it to say that making this game will teach me a great deal about F#, physics algorithms, DirectX, WPF, and C# -> F# interop. I plan on writing everything from scratch - I don't want to use any existing physics libraries, for example - because I want to do some actual learning.