This post was heavily inspired by infographics by Bartosz Adamczewski @badamczewski01 and wouldn’t be possible without sharplab.io by Andrey Shchekin @ashmind and BenchmarkDotNet by contributors.
So I wanted to (re)implemented TimSort for .NET. My previous attempt was relatively successful (well, it worked) but it could be better. Closure of CodePlex (that’s where it was hosted before) gave me perfect opportunity - I need to move it, but I can also rewrite it.
One of the problems with original implementation was the fact that I wanted to have all types of array-like objects (Array
, List
, and IList
). The problem is the choice was (at least that’s what I thought at the time) implementing it 3 times, or implementing it for IList
only and take the performance hit (as accessing Array
though IList
interface comes at the price).
In the end, it was implemented 3 times and do avoid maintaining 3 code bases the actual algorithm was in T4
template (.tt
file) so 3 implementations were generated from it.
Time has shown that I knew very little then…
This post is not about TimSort though (as at the time of writing it is not finished yet). This post is about injecting behaviour into algorithms while retaining original performance.
So, insertion sort is simple O(n^2) sorting algorithm, which actually has some real-life usage. It is actually irrelevant, which one I use for this post, but if I need to use any let’s use the one which is actually has some use cases: it is very fast (O(n)) for data which is nearly sorted and is used as a part of IntroSort combo (quicksort + heapsort + insertion sort). For example, IntroSort is used by .NET.
Let’s start:
1 | public static void Sort(int[] array, int start, int length) |
…and measure baseline implementation:
1 | BenchmarkDotNet=v0.13.1, OS=Windows 10.0.19043.1165 (21H1/May2021Update) |
That’s the problem. It was been tailored for array of ints (int[]
). There are two issues to address: accessing generic indexable data (let’s say IList<...>
) and comparing items (let’s say IComparer<...>
).
That’s super simple! Let’s do it!
1 | public static void Sort<T>( |
That wasn’t hard, was it? Fantastic, problem solved new implementation works for int[]
as well but is completely generic. PROFIT! Let’s just measure performance and go home…
1 | BenchmarkDotNet=v0.13.1, OS=Windows 10.0.19043.1165 (21H1/May2021Update) |
…or not. It is 8 times slower now.
Yes, it is. Simple comparison (most likely one assembler instruction) became a call to virtual method which is (relatively) very slow. What can we do though? Well, not pass interfaces but pass classes, yes? Well, it still would need to be virtual call to make behaviour polymorphic.
How to make a static call to something with polymorphic behavior? This sounds stu… Generics!
1 | public static void Sort<T, TIndexer, TComparer>( |
Now all calls are done to actual class not to interface so when we call:
1 | Sort<int, int[], Comparer<int>>(_data, 0, _data.Length, Comparer<int>.Default); |
it hopefully will get expanded to call actual int[]
not IList<int>
… Let’s measure it:
1 | BenchmarkDotNet=v0.13.1, OS=Windows 10.0.19043.1165 (21H1/May2021Update) |
Oh my, it is not working! It is actually completely identical and it still calls interfaces.
Does it mean that I really need to implement it multiple times, for Array
, List
, IList
and… Span
? Is there any way to implement it just once but use in different contexts?
Wait a seconds… When .NET expands generic class it does it for each value type separately, but not for reference types. That’s why even if int[]
was passed as generic argument it was not generating “dedicated” implementation for int[]
it was still using IList<int>
interface. Let’s try to force it by using value types.
NOTE: I don’t want to use implement whole IList<T>
in my struct so let’s simplify it a little bit as the only thing we actually use from IList<T>
is indexed access:
1 | public interface IIndexer<T> { T this[int index] { get; set; } } |
so now we can implement struct which implements this interface for array:
1 | public readonly struct ArrayIndexer<T>: IIndexer<T> |
We can (re)implement insertion sort using this interface:
1 | public static void Sort<T, TIndexer, TComparer>( |
(NOTE: nothing changed in implementation, just method signature is slightly different)
Seems that BenchmarkDotNet agrees with me as we definitely have improvement:
1 | BenchmarkDotNet=v0.13.1, OS=Windows 10.0.19043.1165 (21H1/May2021Update) |
Let’s do it for comparer as well. The only thing which we actually want from Comparer
in this algorithm is <=
(less or equal), so, let’s make a dedicated interface and dedicated implementation for int
(because that’s what we are measuring):
1 | public interface ILessOrEqual<T> { bool LeEq(in T a, in T b); } |
Now we can modify implementation of algorithm to take this ILessOrEqual<T>
interface:
1 | public static void Sort<T, TIndexer, TComparer>( |
So that would be it, let’s measure:
1 | BenchmarkDotNet=v0.13.1, OS=Windows 10.0.19043.1165 (21H1/May2021Update) |
Yay! We are back to original performance, but with generic algorithm!
Definitely calling this method is little bit cumbersome right now:
1 | Sort<int, ArrayIndexer<int>, IntComparer>( |
but this can be hidden behind some nice overloads and you will have few of them (for T[]
, List<T>
, IList<T>
, or even IDictionary<int, T>
- why not). The story behind Span<T>
is slightly different. Possible, but a little bit more complicated (pinning is required).
The point is it can be almost as fast as dedicated version but also as generic as fully generic version.
Please note, it will be expanded for each indexer/comparer combination so your code will take more memory when JITted, but I don’t think this might be a problem.
I understand NetFabric.Hyperlinq uses same approach with Value delegates to make LINQ a little bit more performant without losing flexibility.
]]>First book I ever read on computer science was “Algorithms + Data Structures = Programming“ by Niklaus Wirth. For a very long time, my favorite one was “Introduction To Algorithms“ by Thomas Cormen. You can see the pattern, right?
It the era of JSON-over-HTTP neither algorithms nor data structures and considered necessary for programming. Actually, it is considered a success if someone choses the right data structure, not mentioning implementing it or, at least, understanding how it works. It is kind of understandable as it is no longer required to understand B+ Trees to use SQL database.
But it helps. And it is fun.
Breadth-First Search is tree traversal algorithm. Because tree is a graph without cycles, by just tracking visited nodes (and preventing cycles) we can use it to build spanning tree of any graph.
I touched the topic of spanning trees quite some time ago while writing about maze generation (which can be implemented as “random spanning tree”).
Breadth-First Search can be expressed with three steps:
1 | let bfs idof fanout node = |
This is neither the most generic implementation of BFS nor the (functionally) purest. For example, both Queue
and HashSet
are mutable data structures and it uses while
loop instead of recurrence, but in this case it is probably most pragmatic one. There is no problem with imperative code in F# (multi-paradigm, functioanl first) as long as it is properly encapsulated. You can read more about this on Eirik Tsarpalis’ blog.
You can see I’m a fan of micro DSLs which allow me express “the essence” without any technical noise. It makes implementation a little bit longer sometimes, but in my opinion, much more readable. There are multiple ways to make this implementation slighlty bit shorter (first step would be using tap/tee
function in few places), but they don’t improve readability so I’ll leave it as it is.
Let’s talk about this function then.
The types are properly inferred by F# compiler and there is no need to declare them explicitly but in this case it would be actually beneficial to do it (adding explicit type declaration on public interfaces is generally a good idea):
1 | let bfs (idof: 'node -> 'id) (fanout: 'node -> 'node seq) (node: 'node) = //... |
So:
idof: 'node -> 'id
: a function which will take the node and generate something which can be considered node’s id; if node is its own id it would be sufficient to use built-in id
function (which is fun x -> x
); please note, that it is actually ids which are stored in HashSet
and used to determine visited nodes;fanout: 'node -> 'node seq
(to be more precise 'node -> 'nodes when 'nodes :> seq<'node>
): a function which will take a single node and return all adjacent nodes (in tree they would be just child nodes)node: 'node
: a starting nodeLet’s test it with some simple tree defined as Map<int, int list>
.
I would use example from wikipedia:
1 | let tree = |
Map.find
(which is int -> int list
) matches almost exactly signature required by fanout
('node -> 'node seq
) but let’s make it a little bit more resilient by using Map.tryFind
:
1 | let fanout node = tree |> Map.tryFind node |> Option.defaultValue [] |
It will try to find node
in tree
and return list of its children. If no children are found it will return empty list ([]
).
Now we can call it:
1 | bfs id fanout 1 |> List.ofSeq |
and… (drum roll):
1 | [1; 2; 3; 4; 5; 6; 7; 8; 9; 10; 11; 12] |
Yay! Exactly as expented. You can add cycles (for example: 2, [5, 6, 1]
) to test if cycles are properly eliminated.
NOTE: To run it in fable.io/repl you will need to polyfill Queue
, for example:
1 | type Queue<'a>(values: 'a seq) = |
One of the examples of tree traversal algorithms is listing directories. I never really cared which tree traversal algorithm, DFS or BFS, is used for that. I was actually suprised that Unix find
works differently than PowerShell gci
(Get-ChildItem
). Apparently, find
uses DFS while gci
uses BFS.
1 | find -type d | less |
1 | gci -r -dir | % { $_.FullName } | oh -p |
Let’s assume I want to do something like Get-ChildItem
(or like find
, but with BFS). How can I implement this using bfs
method?
First question is: what is the node? The node in this case is directory. Directory access in .NET can be done with DirectoryInfo
class from System.IO
namespace. What is fanout
function? This function will take take a directory and return list of child directories. Last thing left is idof
function returning something which can be used to uniquely identify directory. Let’s say full directory name is good enough in this case (although, something like “inode” or “files system object id” would be much better, as it would resolve potential sym-link cycles).
So, having idof
, fanout
and node
defined as follows:
1 | open System.IO |
we can run it with:
1 | bfs idof fanout node |> Seq.toList |
…and get list of all child directories.
Let’s refactor this into a function:
1 | let scanFolders path = // string -> string seq |
which takes path
as input and returns sequence of folder names (scanFolders: string -> string seq
).
We can run it with, for example:
1 | scanFolders "." |> Seq.iter (printfn "%s") |
Please note, that this time we really needed to use idof
as DirectoryInfo
is an object without structural equality so DirectoryInfo(".") != DirectoryInfo(".")
. To compare them we needed something else, something comparable and DirectoryInfo.FullName
look like a good-enough choice.
It would be actually safer to use slightly modified version of fanout
to suppress exceptions in directories which we have no access to:
1 | let fanout (node: DirectoryInfo) = |
Sometimes, apart from getting there (visiting nodes) it is important to know “how we got there” (keeping a history of decisions). We do not want to rewrite bfs
, we would like to reuse it. Let’s call this new method trace
. So far, bfs
is taking node
('node
) and fanout
function (fanout: 'node -> 'node seq
) and returns a sequence of nodes ('node seq
).
This paragraph, describing transformation from bfs
into trace
is probably the most convoluted one in this post. I tried to rewrite it many times but I couldn’t make it simpler (my fault). It is very important though, so please read multiple times until you think you understand what happens here.
We want trace
to return not only a sequence of nodes ('node seq
) as bfs
does but also a history of actions which led to this node: ('node * 'action list) seq
. Look again, instead of sequence of 'node
we want a sequence of 'node * 'action list
. We don’t know nor care what 'action
is. We want it to be provided from fanout
. The new fanout
will not only return a sequence of child nodes ('node -> 'node seq
) but also an action
which caused this transition. New fanout
will be 'node -> ('node * 'action) seq
- taking node and returning sequence of child nodes and actions leading to them. We will reuse bfs
by providing little adapter functions for idof
, fanout
and node
.
Both new node
and new idof
are relatively simple. New starting node is a node with empty action history while new idof
will just ignore action history (as how we got to given node does not affect node’s identity):
1 | let node' = (node, []) |
Adapter for fanout
is a little bit more complicated. The node passed to bfs
is no longer just node, but also contains action history ('node * 'action list
) so fanout
expected by bfs
should be 'node * 'action list -> ('node * 'action list) seq
, but it isn’t. Our new fanout
(for trace
) is (as mentioned before) 'node -> ('node * 'action) seq
. So, we will need another adapter:
1 | let fanout' (node, actions) = node |> fanout |> Seq.map (fun (n, a) -> (n, a :: actions)) |
Now, types match again: fanout
is 'node -> ('node * 'action) seq
while fanout'
is 'node * 'action list -> ('node * 'action list) seq
.
Let me try to explain one more time: fanout'
will take a pair of node
and actions
(leading to this node), it will use fanout
with node
(action history is irrelevant at this point) returning sequence of nodes and actions (n, a
) and create new states with those new nodes and new action prepended to history (fun (n, a) -> (n, a :: actions)
).
So, whole trace
function is:
1 | let trace idof fanout node = |
Please note that new actions are prepended to action list (a :: actions
) so actions will be returned in reversed order. It is not a problem, it is just worth remembering.
Let’s run it using the tree
we used before.
1 | let tree = |
The only question is what we want the action
to be in this case? There is no left or right, as the only decision is down. Let’s use source node as action, so the history of actions will be actually history of nodes.
1 | let fanout node = |
We can run it now:
1 | trace id fanout 1 |> List.ofSeq |
and get the all the nodes with traversal history:
1 | [ |
We can of course process it further, prepending final node to history and then reversing order:
1 | trace id fanout 1 |> Seq.map (List.Cons >> List.rev) |> List.ofSeq |
to transform it to paths:
1 | [ |
This is still not finished thought: trace
calls bfs
while actually it does not care if underlying algorithm is BFS. It would work absolutely perfectly with any other algorithm (DFS, for example). Let’s extract it then:
1 | let trace traverse idof fanout node = |
As you can see, trace
does not call bfs
directly anymore, it expects function of matching signature to be passed to it. bfs
is a perfect candidate, and works perfectly:
1 | trace bfs id fanout 1 |> List.ofSeq |
But now, we could use it with (hypothetical) dfs
by just changing it to:
1 | trace dfs id fanout 1 |> List.ofSeq // NOTE: you would have to implement dfs yourself |
Please note, that with one trivial adapter function (idof'
), one relatively simple adapter function (fanout'
) and injectable traversal algorithm (bfs
, dfs
or… whatever matches the signature) we have completely new functionality (tracing). Composite Reuse Principle, Single Responsibility Principle, Open/Closed Principle, Interface Segregation Principle and Dependency Inversion Principle. All of those in 5 lines of code.
The idea of doing Bloxorz solver comes from Functional Program Design in Scala course. It is a second week assignment. In does not explicitly mentions BFS as it tries to teach lazy evaluations rather than graph algorithms, but I find a great example how to use BFS.
Unfortunately, it is quite hard to explain how it works, so you will need to play Bloxorz yourself on, for example: http://www.bloxorz.org.uk/ (you will also need to enable Flash). If it doesn’t work just google “bloxorz” and you may find multiple sites allowing you to play. If it is year 2050, Flash no longer works, and nobody ported Bloxorz to ES2050, but YouTube still works you can check what it was about here:
If you have a feel how Bloxorz work we can start. We will address only the simplest scenarios: no weak squares, no block splitting and no dynamic environment. While weak squares could be actually quite easy to implement, block splitting and dynamic environment would bring a lot of complexity to solution.
As I already hinted we will use BFS to solve Bloxorz puzzles. Knowning that we need to establish what node
will be, what idof
should return and how fanout
should work.
The node is the state/position of the block. The child/adjacent nodes are the valid nodes which can be reached by moving block in any direction. Valid node is the node where both parts of the block are on valid squares. The solution is the path (history of actions) leading to target block position while target block position is block “standing” on top of the goal. Yeah, that’s why you need to play Bloxorz for a while to get a feeling what all those things mean.
Let’s start with a little bit of domain:
1 | type Position = int * int |
For functional purists: I have to admit that this domain model violates make illegal state unrepresentable principle. For example, we can define split Bloxor
while we said we are not handling them. We can also construct a World
when one or both (starting and target) positions are illegal. Although, I decided that domain design for Bloxor problem is not really a main topic here.
So, we have Position
which represents X and Y coordinates in Bloxor space. We have Bloxor
which is a pair of positions (as it consists of two pieces). We have World
which has starting position (A
), target position (B
) and a function answering the question: is given position legal (takes Position
and returns true
or false
).
Let’s define infinite World
first:
1 | let infiniteWorld a b = { A = a; B = b; IsValid = fun _ -> true } |
Please note that IsValid
always returns true
, which means any position is legal, we can roll our bloxor wherever we want. We will implement more complex worlds later but this one will allow us to have something to test our algorithm with.
Let’s define some functions around bloxor behaviour and state. First, makeBloxor
will allow us to create a standing bloxor at given position. This is a lot of text to create tuple of points (p, p)
but let’s make it official:
1 | let makeBloxor (position: Position): Bloxor = (position, position) |
The other helper function would help us determine what is current bloxor orientation:
1 | let (|IsStanding|IsHorizontal|IsVertical|) (bloxor: Bloxor) = |
I assume you are familiar with active patterns, but even if you are not, please imagine three methods (IsStanding
, IsHorizontal
and IsVertical
) so similar that thay share single body… Well, it does not make it any clearer. I guess “Multi-Case Active Patterns” section on Chris Smith’s blog explains it better.
This active patterns deconstructs bloxor and recognizes its orientation: standing, horizontal or vertical. It may also throw an exception when bloxor is invalid (including split or just inverted). It requires some discipline how bloxor is constructed but as I said before, MISU principle is not a main concern here.
Next step is to define how bloxor moves. This is really messy function (all those shiftY -2 -1
and shiftX -1 -1
) but describes all possible moves (North
, South
, East
, West
) from all posible startings orientations (IsStanding
, IsHorizontal
, IsVertical
). It decides how bloxor coordinates should be adjusted (let move = match bloxor, direction with ...
) and returns new bloxor position (move bloxor
).
1 | let moveBloxor (bloxor: Bloxor) (direction: Move): Bloxor = |
The rules were slowly reconstructed from this picture:
We are ready to write solver function. The solveWorld
function will take World
(as World
is the problem to solve) and return Move list option
. We could alias Move list
as Path
and then returned type would be Path option
. It returns option
as it possible that solution cannot be found.
1 | let solveWorld (world: World): Move list option = // ... |
Let’s go slowly through DSL for this function:
1 | let solveWorld (world: World): Move list option = |
isValid
: bloxor position (deconstructed into a
and b
) is valid when both pieces are valid;isFinal
: bloxor position (deconstructed into a
and b
) is final when both pieces are in final position (meaning: we found the solution);validMoves
: try to move bloxor in all directions ([North; South; East; West] |> Seq.map moveBloxor
) creating pairs of new bloxor positions and move directions (note: node
and action
) but filter out all invalid moves (Seq.filter isValid
);We are ready now solve bloxorz! The whole function is:
1 | let solveWorld (world: World): Move list option = |
Where:
node
: bloxor initial position at world.A
;idof
: bloxor position unique identifier - it is just a string with coordinates of both pieces; because of structural equality in F# this is not really needed (built in id
would be sufficient) but it wouldn’t work in Fable (HashSet
is not fully compatible);fanout
: it is actually validMoves
- for every bloxor position returns a sequence of new valid bloxor positions with appropriate moves (Bloxor -> (Bloxor * Move) seq
) which is exactly when we wanted for trace
('node -> ('node * 'action) seq
).So, the last expression is actually running it (trace bfs idof fanout node
) which returns a sequence of all paths, and finding first one (shortest!) leading to solutions (Seq.tryFind/isFinal
) and taking only the history part (fun (_, actions) -> actions
) and reverses it (List.rev
). If you’re fan of point-free style, this can be also expressed as:
1 | trace bfs idof fanout node |> Seq.tryFind (fst >> isFinal) |> Option.map (snd >> List.rev) |
Let’s try it first with inifinite world:
1 | infiniteWorld (0, 0) (1, 0) |> solveWorld |
produces:
1 | Some [North; East; South] |
which is the correct answer: solution was found (Some
) and the path was North
, East
, South
.
Let’s try a longer path, for example from (0, 0)
to (9, 9)
. We expect it be 6 times South
then 6 times East
(or the other way around: 6 times East
then 6 times South
).
1 | infiniteWorld (0, 0) (9, 9) |> solveWorld |
returns:
1 | Some [South; South; South; South; South; South; East; East; East; East; East; East] |
which confirms our expectations.
As a last step, we can add ability to define more complex worlds. Let’s assume we would like to define world using ASCII, for example:
1 | let world = [ |
would represent:
Note, space represents empty sqaure while A
and B
are initial position and target position respectively.
We need to create a map of characters (Map<int * int, char>
) first:
1 | let map = |
This does not look too attractive as, in general, nested loops with indexes are not the prettiest constuct in functional languges. The general idea here is to iterate over lines (world |> Seq.mapi
) then over characters in line (l |> Seq.mapi
), flatten nested list (Seq.collect
) and create a map (x, y) -> c
(Map.ofSeq
).
Having such a map we can determine initial and target positions:
1 | let a = map |> Map.findKey (fun k c -> c = 'A') |
and define a function which will test if given position is valid:
1 | let valid k = map |> Map.tryFind k |> Option.filter (fun c -> c <> ' ') |> Option.isSome |
Having these three bits of information we can construct a World
record:
1 | { A = a; B = b; IsValid = valid } |
Let’s put all those things together:
1 | let parseWorld lines = |
For OO fans I would like to emphasize, that you can think about infiniteWorld
and parseWorld
as two constructors of two different objects implementing the same interface (World
).
So, let’s try this example:
1 | let world = [ |
It returns:
1 | Some [ |
I can bet that’s exactly what we need (you can go to http://www.bloxorz.org.uk/ and use 918660
as stage code).
I wrote simple Fable app which shows results as animation:
…you might ask. Good question. You need to watch this first (ok, YouTube keeps removing this clip, so if it is gone, try this link):
We have solution space (two containers), we have allowed moves (fill, empty, transfer) and a goal (one container contains exactly 4 gallons). Well, this problem is identical to Bloxorz, isn’t it?
Let’s start with domain:
1 | type Jug = | A | B |
Jug
: we have two jugs: A
and B
;Action
: possible actions are emptying a jug (Empty
), filling a jug (Fill
), or transferring water from one jug to another (Transfer
);State
: state of the system with current and maximum levels;Let me try to draw it:
We can add some methods to State
to make working with this record a little bit easier:
1 | type State = |
Where:
Get
: gets jug level;Max
: gets jug capacity;Empty
: empties given jug;Fill
: fills given jug;Transfer
: transfers water from one jug to another (until source jug is empty or target jug is full);These three last methods (Empty
, Fill
and Transfer
) map directly to Action
cases:
1 | let applyAction (state: State) action = |
Having all this we can attempt to save New York, and in principle, it is the same operation as solving Bloxorz:
1 | let saveNewYork target state = |
We can identify visited states with idof
to avoid running in circles, we can transition to new states with fanout
by executing all the possible actions ([Empty A; Empty B; Fill A; Fill B; Transfer (A, B); Transfer (B, A)]
), and we can check if we reached our goal (isDone
). The last step is actually to scan solution space (trace bfs idof fanout state
), terminating search when appropriate (Seq.tryFind
) and reversing action history (as it is upside-down).
Let’s try:
1 | let newYork = State.Create(3, 5) |
which returns:
1 | Some [Fill B; Transfer (B,A); Empty A; Transfer (B,A); Fill B; Transfer (B,A)] |
Hmm, let’s replay all actions to see if it really worked. To do that I will actually use some dreaded imperative code:
1 | let newYork = State.Create(3, 5) |
which generates readable description what has happened:
1 | 0/0 -> Fill B -> 0/5 |
and, yes, in fact we end up with 4 gallons in jug B. New York is saved!
Please note, functional purists might say I should not use imperative loop with mutable variable, and use Seq.scan |> Seq.iter
instead. To be honest, I did that at first, but this imperative loop is actually much more readable even if not pure enough.
Let’s try something bigger:
1 | State.Create(113, 97) |> saveNewYork 66 |
returns:
1 | Some [ |
Let’s see it it crashes, or hangs up when there is no solution:
1 | State.Create(12, 6) |> saveNewYork 4 |
Nope, it works just fine and returns None
.
I really like the idea that three seemingly different problems (scanning folders, pushing Bloxorz through the hole and saving New York) are actually the same problem, and all of them can be solved with the same function and a little bit of “adaptation”.
I also really liked the idea that it is possible to present 4 (out of 5) SOLID principles (plus CRP) in 5 lines of code and the fact that they come quite naturally in FP. Oh irony! OO principles are intrinsic to FP.
Other than that? Well… I don’t think my day-to-day JSON-over-HTTP activities require a lot of “Saving New York”, but when they do, I’m ready :-)
Let’s start from scratch. You know all the things you read in previous article, but you have no code at all.
So we said that SAM interfaces are technically equivalent to functions (to be precise: Func
or Action
depending on return type). So, let’s see where it can get us.
Knowing the interfaces were declared like this:
1 | public interface ILogger { |
we can redefine them as:
1 | // pseudo-code |
Now, we can substitute ILogger
actual type (Action<...>
) as ILoggerFactory
output type, receiving:
1 | // Pseudo-code |
So, the interface to logging framework is just Func<string, Action<Severity, Func<string>>>
, and next time someone ask you on the tube, “Hey man, what’s your Func<string, Action<Severity, Func<string>>>
?” you can just tell him: “I’m using log4net, matey”.
In my opinion, using descriptive names depends on scope. I would actually encourage you to use just Func<T>
for locally scoped or internal factory, or i
as an index in 3-line for statement but for objects which are known by entire application I would prefer longer, more distinguished names.
In case of “logging framework interface” I would suggest quite descriptive names. Yes, it is just a function, but it would be much more readable if we call it LoggerFactory
.
Let’s do it then:
1 | public enum Severity { Trace, Debug, Info, Warn, Error, Fatal } |
That’s our interface.
So, the NLog implementation we did in previous article will look now a little bit different:
1 | public static LoggerFactory NLogLoggerFactory() |
You can see that we declared a factory method which can be called LoggerFactory
constructor. A LoggerFactory
will construct a Logger
every time you call it with logger name (name => { ... }
). A Logger
will log the message when called with severity and (message) builder ((severity, builder) => { ... }
).
If you need simplest possible implementations of LoggerFactory
I would say it would NullLoggerFactory
followed by ConsoleLoggerFactory
:
1 | public static LoggerFactory NullLoggerFactory() |
Let’s look at specific usage. You have to create a logger factory first (you need one of those):
1 | var loggerFactory = NLogLoggerFactory(); // or ConsoleLoggerFactory() ? |
Then, you can create loggers when you need them:
1 | var logger = loggerFactory("default"); |
and log messages like you always did:
1 | logger(Severity.Warn, () => "Something is rotten in the state of Denmark"); |
You can also just sprint through all the layers:
1 | loggerFactory("root")(Severity.Trace, () => "Adhoc message"); |
Job’s done. That’s what we wanted.
It is not. There is only one way to use it but wasn’t it a good thing?. Joking aside, we want our extension methods back. Good news is, all you need is to ask:
1 | public static class LoggerFactoryExtensions |
So now you can use extension methods on LoggerFactory
or use LoggerFactory
as a function (yes, it may look confusing):
1 | // just call *it* |
In previous article we’ve introduced message Severity
to reduce number of overloads, but when we added convenience methods there was 24 of them again (still better than 24 to be implemented on interface though). Let’s try to apply same tactics and normalize convenience layer as well. We can create new “interface” (it’s not technically an interface
but it is still an interface). Let’s call it Channel
(like Trace, Debug or Error channel).
1 | public delegate void Channel(Func<string> factory); |
As you can see, Channel
is like a Logger
, but without Severity
, as Severity
has been already applied. We can add some convenience methods as well:
1 | public static partial class LoggerExtensions |
Now you can use like this:
1 | var channel = logger.Trace(); |
There is still only one way to format a message (using Func<string>
). Although, we have a type (Channel
) we can add extensions methods to it:
1 | public static class ChannelExtensions |
So, now we have all convenience methods back:
1 | var logger = loggerFactory.Logger(); // for this class |
Syntactically, I don’t like the parenthesis after channel (Trace, Debug, etc.). Unfortunately, we don’t have extension properties yet (C# 8, maybe?). As soon as they are available, they could be used to strip parenthesis from channel selection and produce prettier code:
1 | var logger = loggerFactory.Logger(); // for this class |
Nice, isn’t it?
So, complete implementation of the interface with extension methods is:
While adapter for NLog could be implemented like:
Definitely, message expansion (builder()
) should be wrapped in try...catch
so badly formatted message cannot blow up the application. It would suggest doing it in Logger.Channel(this Logger logger, Severity severity)
as everything ultimately goes through this function (yes, it is by design - there is only one place where it needs to be done).
I would also invest in better error.ToString
to log exception. Some Func<Exception, string>
(of course) which would explain the exception, processing inner exceptions and stack traces.
Convenience methods can be still added to Logger
: like Log(Severity, ...)
, and all 24 overloads for Trace(...)
, Debug(...)
, etc. I didn’t do it here, as they are not really needed anymore, but if you really like them there is no problem to do so (see GitHub project for T4 implementation).
This project is available on GitHub. Please note, this is just a toy project to present some ideas rather than production ready solution.
]]>This introduction is for hard core OO developers (mostly C# but maybe Java as well) who are trying to add FP to their skillset. If you are FP developer, you most likely know all those things.
SAM is the term introduced in Java 8 and means “Single Abstract Method”. It’s describes an interface with only one method. Of course, we had them before (both in Java and C#):
1 | // C# |
but they became more visible in Java 8, as they were used to implement very important language feature. We will talk about this in few moments.
Designing your system with SAMs has some quantifiable advantages.
First of all, it helps with Single Responsibility Principle and Interface Segregation Principle. Don’t get me wrong, it is still possible to do it wrong, and create single method with multiple responsibilities. Actually, some of the solutions presented in this article are not the purest, but they are, I hope at least, move in the right direction.
Second, your SAM interfaces are easier to implement. Did you ever try replace a component and found out that interface you need to implement has 50 methods? It just smells like “Oh, we had this God Object with some random methods and doing everything, but someone told us we need interfaces so we extracted every single possible method, job’s done”. They usually never get implemented again.
Third, they are easier to mock. I’m kind of reiterating second point here: they are easier to mock as there is only one method to fake, stub or mock (it’s not the same, I know, but whatever you call it, it’s still easier). You may say, that for bigger interfaces, you still need to mock only one method for a particular test. But which one, I would ask? Oh, the one which given test actually uses. Really? So now, you are making assumptions how exactly tested method works, instead of providing dependencies are checking if it satisfies acceptance criteria? Why testing it at all then? It is also a recipe for brittle tests. Change implementation a bit and your test will start to fail because your function under test calls different overload now (for example, the one with timeout passed as TimeSpan
rather than int
). Design it with SAM at there will be only one method to mock.
Oh, I forgot to mention, Functional Programmers also have a name for SAM, they call it… a function.
Java has anonymous classes for injecting behaviour since 1997 (Java 1.1), so in Java world the concept is not new at all. Using them was just very clunky:
1 | interface Action<T> { |
If you look closely, the anonymous class implementing Action
interface in printAll
is what we would call lambda in C#. It is just completely wrist-unfriendly.
When lambdas were added, they wanted all those functions to support lambda. Who doesn’t like lambdas? Right? But they couldn’t just change them, as Java is all about backwards compatibility. Duplicating every method (to accept anonymous class or lambda) would be a huge task. They decided, and so far it seems like a smart move, that they won’t change the interfaces, they will just modify the compiler to generate those, a little bit inflated, anonymous classes for you (NOTE: this isn’t exactly true, Java 8 implementation of lambdas is actually quite optimized):
1 | interface Action<T> { |
From inside of forEach
method nothing has changed, it still “thinks” it works with class implementing Action
interface, but this class has been generated on the fly (well, again, not exactly true, but good-enough) from lambda.
This mechanics immediately breaks, of course, when expected interface has more than one (abstract) method, as we can only implement one with lambda function.
Anyway, what’s important to remember is the fact that interface with single abstract method is technically a function, and a function is technically an interface with single abstract method, for example, with IComparer
and Comparison
defined below:
1 | public interface IComparer<in T> |
we can easily implement conversion function both ways: converting IComparer
to Comparison
is trivial as IComparer.Compare
is-a Comparison
while conversion the other way around would require a wrapper:
1 | public class AdhocComparer<T>: IComparer<T> |
I will point this fact again later, but please note that this is not a coincidence that converting to FP is usually trivial, while conversion to OO requires a little wrapper. Usually (at least) 4 lines: a class declaration, a field to store the function, a constructor to take function as argument, and single abstract method calling this function. That’s exactly what Java compiler does.
Nevertheless, SAM is function, function is SAM.
If you ever used NLog
or log4net
you can imagine a ILoggerFactory
and ILogger
interfaces to be declared like this:
1 | public interface ILoggerFactory |
Right? With ILoggerFactory
we can get logger with given name, logger for given type, or for given type but passed as generic, and maybe a logger for current scope (most likely it will be a class). With ILogger
you can log messages of different severity (Trace, Debug, Info, etc.), and provide messages in few different ways: as a string, or maybe as a pattern to be expanded when logging, with or without Exception
.
Anyway, great, let’s start implementing it. Method by method… Just joking.
It is one of those interfaces you should really ask: I really like all those methods, and I want them to be available but do I need to implement them all? No, you don’t.
Let’s start with ILoggerFactory
as it is much easier. You can notice that somewhere on the end, regardless which method on ILoggerFactory
we call, we end up in Logger(string)
as this is logger’s primary constructor and all other methods use it in some way:
1 | ILogger Logger(Type type) => Logger(type.FullName); |
There is nothing in their implementation which would require them to be re-implemented in every possible implementation of ILoggerFactory
. So, technically, this interface should be actually reduced to:
1 | public interface ILoggerFactory |
Single. Abstract. Method.
Although, you want all the convenience methods to be available. Right? Right.
I can think of three obvious ways to deliver them to the potential user:
ExtendedLoggerFactory
, which takes ILoggerFactory
in constructor and delivers additional functionality.ILogger Logger(string)
left as abstract. No interface, just base class, let’s say LoggerFactoryBase
(yup, a kitten just died somewhere).ILoggerFactory
as this
For completeness, I have to say, that Scala has traits and implicit wrappers, while Java gives you default methods. It is outside of the scope this article, but worth googling (even if you are C# developer).
There are pros and cons to all of those solutions.
The wrapper class is probably the cleanest from OO perspective, but a little bit confusing and clunky: we implement ILoggerFactory
but pass ExtendedLoggerFactory
(alternatively, we can also pass ILoggerFactory
and rewrap it all the time). Most of the clunkiness of this solution disappears when using IoC container (we always inject ExtendedLoggerFactory
leaving ILoggerFactory
for library developers).
Abstract class does not have this problem but enforces specific base class, pulling all the dependencies with it. It’s a viable solution, but I tend to stay away from partially implemented abstract classes.
Extension methods are quite controversial, as your extension methods are not polymorphic at all. Once defined, they cannot be overridden. With some functions it is not a problem as there is not “other” implementation of LINQ Where
or Select
, but it is possible to get it too far. If you think your extension methods may be controversial “hide” them in some namespace with needs to be imported explicitly, for example: LoggingFramework.Extensions
. It you think they are just fine, put them into the same namespace as interface, let’s say LoggingFramework.Core
. If you think they are so great that everyone should use them day and night, stick them into System.Linq
(and add all the warning suppression directives). Definitely, this can make development very easy (because extension are always available thanks to IntelliSense), or it can make you very unpopular (for exactly the same reason). Use them wisely.
In this article I decided to go for extension methods. I think this approach is relatively pragmatic, never had problem with it in a field and even if there is a potential flaw, the net effect is positive. Actually, Reactive Extensions are using the same technique (just check what is available on IObservable<T>
interface with and without System.Reactive
namespace imported).
So, after this long introduction, the declaration of the interface and implementation of convenience methods:
1 | public interface ILoggerFactory |
Single method on the interface, and some extension methods, which are just redirecting calls to that interface.
ILogger
is quite big. It is also quite repetitive:
1 | public interface ILogger |
Please note, that the methods here are Cartesian product of all choices we can make:
string
, Func<string>
and string, params object[]
)So we have 6 x 2 x 3 = 36
methods.
Let’s move one of the choices out of the interface, and introduce Severity
enum. It will reduce this interface to just 6 methods:
1 | public enum Severity |
It’s the same technique you might have used for database normalization.
Next, I think that doubling number of overloads, only because we can call it with or without Exception
is unnecessary, one dedicated overload for Exception
is enough:
1 | public interface ILogger |
Before we proceed it might be important to explain why these method pair exists (not only in our implementation, but in general, in all logging frameworks):
1 | void Log(Severity severity, string message); |
Isn’t the second one equivalent to calling first one with string.Format(...)
(or with $"..."
)?
1 | Log(Severity.Error, pattern, arg1, args2, ...); |
Well, effect is the same, but side effects are different. When we leave expansion to the logging framework it won’t be done if logging is disabled (let’s say in production we do not log Severity.Trace
). When doing string expansion yourself (string.Format
or $"..."
) you do this before framework has a chance to decide if logging is enabled, so you do this even if expanded string is going to be swallowed, wasting CPU cycles and risking exception being thrown during this operation.
We already have deferral mechanism in this interface, though: Func<string>
. Actually, all those four overloads can be implemented using only one method on interface and convenience method on extender:
1 | public interface ILogger |
NOTE: Exception.ToString
is Func<string>
Of course, we want our convenience methods back. Let’s add them as extension methods, using T4 template engine this time (we could do this by hand, as this is generated only once, but using T4 is useful skill to have):
1 | public static class MoreLoggerExtensions |
Note that these methods are not necessary, they do not add new features. They are just convenient redirects. They do not have to be implemented ever again as long as ILogger
has single abstract method void Log(Severity severity, Func<string> builder)
.
So we need to implement these two interfaces:
1 | public interface ILoggerFactory |
to make NLog compatible with our logging facade. Let’s do it…
First thing which definitely needs to be addressed is the fact that NLog does not “understand” our Severity
. It uses its own enumeration called LogLevel
. We need to translate it:
1 | private static LogLevel ToLogLevel(Severity severity) |
Second thing is, NLog does not have an overload taking Func<string>
. It has the one taking a string
or a string, params object[]
. We can settle with the string
version and use:
1 | var level = ToLogLevel(severity); |
There is another way to do deferred expansion, though. It involves small wrapper class (again!) taking Func<string>
and calling it in .ToString()
:
1 | private class DeferredToString |
Now, we could use it like this:
1 | logger.Log(ToLogLevel(severity), "{0}", new DeferredToString(builder)); |
but, even if I actually like it more, it is not necessary and it has some negative performance implications. As I said before, the sole existence of this 4 line class is admission that OO design is not as expressive as FP.
Both ways, it will work just fine, and the implementation is:
1 | public class NLogLoggerFactory: ILoggerFactory |
Done. Now NLog is compatible with our facade.
So, let me reiterate, as might have disappeared in wall of text:
This is The Interface:
These are The Extensions, a set of functions we extracted from interface, as they don’t really need to be there:
The third part is The Convenience Layer, an even bigger set of functions, which do not added functionality but make typing easier:
Please note, that this is not a .cs
file, it is a .tt
file, I just used .cs
extension on gist to have syntax highlight. The expanded version of this template can be found here
The last part, most likely in different assembly (as it has third party dependency) is The Adapter, adapting actual implementation to our abstract interface:
We reduced the interface surface from 40 methods (36 + 4), to 2 without affecting functionality, all you need to implement (or fake) logging system is this:
1 | public interface ILoggerFactory |
All the methods are still available, though:
You can go further with SAM by using just functions. Please read second part here.
]]>This is just an update to previous blog-post titled Kruskal, Kotlin, and Hex Tiles. I assume you read it, otherwise some things may not make sense.
We already tried Depth-First Search and Kruskal’s algorithm. They both have some disadvantages. Depth-First Search has low branching factor, meaning that is does not branch unless it gets stuck, so it actually can create one very long path through the whole maze to the point where it is hard to call it “maze” anymore.
On the other side there is Kruskal’s algorithms which is all about branching. The problem with branching is that even if it creates a dead-end the length of dead-end branch is quite often low (let’s say one or two “rooms”) and is very easy to spot.
The “challenge” was to create algorithm which is a hybrid of Depth-First Search and Kruskal’s algorithm.
For this I needed a DFS algorithm using the same domain model as previously implemented Kruskal’s algorithm. It assumed existence of nodes and edges, having no constraint on node (vertex) and expecting edge to be a pair of nodes (vertices):
1 | interface Edge<N> { |
Algorithm itself had very simple interface, it was taking a sequence of edges (most likely randomized), and provided a method called next()
returning next edge forming spanning tree. Please note that in languages with generators (Kotlin is not blessed with them, yet) it could be implemented as function taking a sequence of edges (Sequence<E>
) and a returning sequence of edges (Sequence<E>
). It had to define method next()
instead which just returns next edge (equivalent of yield return
) or null (kind-of yield break
) if no more edges can be found:
1 | class Kruskal<N, E : Edge<N>>(edges: Sequence<E>) { |
This algorithm will have similar interface (although there is no explicitly defined interface
) returning sequence of edges:
1 | class Trailblazer<N, E : Edge<N>>(...) { |
I called it Trailblazer
because it is not exactly a Depth-First Search as it does not have backtracking. Backtracking in DFS is used to handle dead-ends (by branching), while in this hybrid algorithm branching is handled by Kruskal’s algorithm, so trailblazer is expected to just push forward.
There is a slight impedance between model used by Kruskal’s algorithm and Trailblazer, so the latter will use some helper methods to adapt:
1 | class Trailblazer<N, E : Edge<N>>(edges: (N) -> Sequence<E>) { |
it will need a function (edges
) which will provide sequence of edges going out of given node. It will need a set of already visited nodes (visited
) and current location (head
).
Edges in “Kruskal’s” model are just a pairs of nodes, while for Trailblazer direction is very important. Therefore we will need a method to find “opposite end” of an edge:
1 | private fun opposite(node: N, edge: E): N? = |
we will also need mark visited nodes and optionally move head
to newly visited one. This method will also return true
if node has been just added (meaning has not been visited before):
1 | fun visit(node: N, reset: Boolean = false): Boolean { |
This does not look pretty, I have to admit, but it helped keep next
method quite short:
1 | fun next(): E? { |
I actually like val current = head ?: return null
syntax. Kotlin allow you to put control statements like return
, break
and continue
in places where you would expect expressions, when it makes expression value irrelevant. In this case it will extract value from nullable head
and put it into current
, or it will exit this method returning null
immediately. It’s kind-of “something or die()” in PHP.
After that, it takes all edges
going out of current
node and finds first which opposite
end has not been visited yet. So it is exactly like DFS, it just does not have backtracking.
These two (Kruskal and Trailblazer) algorithms will have to work together, and they need to expose some methods for communication.
First, Kruskal, needs to expose ability to merge node sets (it is the most important concepts in Kruskal’s algorithm, so if you don’t know what I’m talking about please refer to previous blog-post):
1 | class Kruskal<N, E : Edge<N>>(...) { |
On the other side of the fence, Trailblazer algorithm will need to be restarted every time Kruskal jumps from one location to another:
1 | class Trailblazer<N, E : Edge<N>>(...) { |
That’s all we need.
Let’s do the Hybrid
algorithm now. It will use the same “interface”, of course:
1 | class Hybrid<N, E : Edge<N>>(edges: Sequence<E>, threshold: Double, rng: () -> Double) { |
On top of usual stuff (sequence of edges) it will also take random number generator (rng
) and a threshold
which will control how biased towards Trailblazer (0.0
) or Kruskal (1.0
) it will be.
It will also need a function returning outgoing edges for Trailblazer. Let’s start with building a dictionary (map) of all edges:
1 | private val map = mapEdges(edges) |
It goes through all edges
and for both ends (nodes A
and B
) adds this edge as outgoing (link
). So, the result
is a dictionary from nodes to list of edges (Map<N, List<E>>
). There might be an important question to ask here, if those lists need to be shuffled again, but I assume that input sequence was already shuffled, so shuffling already shuffled sequence does not increase its randomness. Although, in this case, there is a chance I’m completely wrong.
We can use this dictionary to define function needed by Trailblazer algorithm (see Trailblazer’s constructor):
1 | private fun getEdges(node: N): Sequence<E> = |
All those question marks are to handle potential misses (and propagate nulls instead of throwing exceptions). So, what this function does is finds a node in dictionary and returns a sequence of edges incidental to this node or, in case node was not in dictionary, it return empty sequence.
Hybrid algorithm encapsulates both algorithms, original Kruskal
and Trailblazer
algorithms:
1 | private val kruskal = Kruskal(edges) |
it also combines next
functions from both:
1 | fun next(): E? = nextTrailblazer() ?: nextKruskal() |
which means: try Trailblazer first, and if it fails, try Kruskal’s. If both of them failed then that’s it.
First let’s implement about nextTrailblazer
:
1 | private fun nextTrailblazer(): E? = |
As you can see, it makes a call if it should use Trailblazer algorithm in this step at all. For example, if threshold
is set to 0.1
there is a 10% chance on every step that Trailblazer will stop and switch back to Kruskal. Therefore for threshold
set to 1.0
it would be working exactly like original Kruskal and Trailblazer’s step would never be executed. For threshold
set to 0.0
it would strongly prefer Trailblazer switching to Kruskal only when Trailblazer hit dead-end.
If it decided to use Trailblazer and Trailblazer actually found an edge, both ends of this edge are added to Kruskal’s disjoint-set, making Kruskal’s part of the algorithm aware of this edge being returned.
On the other side, nextKruskal
is implemented as follows:
1 | private fun nextKruskal(): E? = |
It takes next edge from Kruskal’s algorithm and if it succeeded, adds marks both ends as visited for Trailblazer algorithm and resets Trailblazer’s starting location.
There is not really too much to do in presentation layer, there are two lines which have been modified. Actually, it’s still one line too much. If Kruskal
and Hybrid
implemented same interface from the start it would just one line, but adding interface now is a little bit too late - I just want to make it run. Anyway, it there was an interface it would be interface Sequencer<T> { fun next(): T? }
.
So, the lines we need to change:
1 | // here: Kruskal -> Hybrid |
It seems that it does exactly what I intended. That’s how it looks after few steps:
I really liked OCP in action. I mean, it did require one line to be added to Kruskal’s algorithm to make it work, but arguably merge
method should be exposed from the beginning or disjoint-set (sets
) should be injected into it. Anyway, Kruskal
class has been completely reused, and new algorithm (Hybrid
) composes Kruskal
and pseudo-DFS (Trailblazer
) quite nicely. I could polish it a little bit, but I think it is good-enough.
You can find sources here or you can just use online demo
]]>So the next approach, after Randomized depth-first search, Randomized depth-first search with stack shaking, Random spanning tree with Prim’s algorithm, to maze generation is Kruskal’s algorithm. Technically, it’s still the same thing: random spanning tree, it’s just different approach. This time the new tech to try was: Kotlin and Jade/Pug. I didn’t do too much Jade, I just wanted to try, but I have to say again: Kotlin… good stuff.
Kruskal algorithm, is quite simple to describe:
To apply Kruskal’s algorithm to maze generation we don’t need to do “minimum spanning tree” as “random spanning tree” is enough. So “take edge with lowest weight* should be replaced with “take any edge”. To achieve that we can just shuffle all the edges before feeding them to the algorithm. Let’s write a shuffle
method to shuffle array in-place, and shuffled
function returning a shuffled version of given sequence:
1 | fun <T> MutableList<T>.swap(x: Int, y: Int) { |
NOTE: If you are unfamiliar with Kotlin it might a little bit obscure. All three methods above are extension methods (familiar for C# users), and for all of them this is implicitly pointing to the object they have been executed for. So, this[x]
(in swap
) is accessing element x
in MutableList
, size
(in shuffle
) is the length of MutableList
. Extension method apply
is a different story.
The only challenge is “cycle detection”. I used disjoint-set data structure, and I strongly recommend reading my other blogpost.
For Kruskal’s algorithm we need to define an Edge
:
1 | interface Edge<N> { |
which is just an entity connecting two nodes, A
and B
. The algorithm itself is very simple:
1 | class Kruskal<N, E : Edge<N>>(edges: Sequence<E>) { |
One challenge, as mention before, is “cycle detection” which is handled by DisjointSet. It also, to allow animation, returns only one edge at the time (see next
). So what it does?
It takes a sequence of edges
as input. They are assumed to be in right order, sorted by weight for minimum spanning tree, and randomized for random spanning tree. It creates empty DisjointSet
to track cycles. On each step, it checks if there are still edges to test (iterator.hasNext
). If so, it takes next edge and check if it would form a cycle (sets.test
). If it would, it tries next
edge, if it wouldn’t it adds this edge to solution (sets.merge
) and returns it.
That’s kind of it. Rest is just presentation.
All algorithms I was using so far were in square grid space, but they did not need to be. So for this one I decided to build a maze of hex tiles.
It added some complexity to coordinates and drawing. I won’t be getting into details as there is a lot of websites talking about hex tiles as they are foundation of many games. If you are interested just start here.
The domain model is quite trivial:
1 | data class Tile(val x: Int, val y: Int) |
there are tiles and they are connected with doors. It is worth noting that Door
implements Edge<N>
interface.
Building the world in rectangular space wasn’t particularly tricky but required some pen and paper experiment to get connection right:
1 | fun buildWorld(width: Int, height: Int): Sequence<Door> { |
The method above returns a an ordered sequence of doors (we will need to shuffle them for the algorithm).
Presentation layer is a little bit messy to be honest, but I just wanted to make it work. Using image below and some primary school maths
we can calculate positions of tiles in pixels and needed size of canvas:
1 | val TILE_COLOR = "#fff" |
On top of that we can draw tiles as well:
1 | fun Tile.paint(context: CanvasRenderingContext2D) { |
Just note that these paint
functions are extension methods for Tile
and Door
respectively.
The only remaining thing is presentation and some user interaction.
We need to get references to some DOM elements:
1 | val canvas = document.getElementById("main") as HTMLCanvasElement |
then configure canvas:
1 | val size = worldSize(WORLD_WIDTH, WORLD_HEIGHT) |
and attach event listener to Restart button:
1 | button.onClick { |
which will potentially kill previous animation, clear the canvas and start new animation.
Let’s implement those. Clearing canvas is just about painting it black:
1 | fun clear() { |
Starting animation is a little bit more complex:
1 | var handle: Int? = null |
It does have a handle
(nullable int) to store timeout handler so we can cancel it if needed. We starting animation (launch
) it generates all the edges (buildWorld
) and shuffles them (shuffled
). Then passes this sequence of edges to animate
function which is handling one edge at the time using a timer (window.setTimeout
). It takes next edge (algorithm.next()
), paints it (paint
) and schedules next step (handle = window.setTimeout(...)
). It worth noting that when first null
edge is returned the whole loop stops.
Finally, the cancel
method:
1 | fun cancel() { |
which just cancels potentially scheduled “next step”, therefore cancelling whole animation.
This is very subjective but Kotlin seems to me to be most polished from all languages I’ve tried. But they are all really good. Fable has a lot of community behind it, Scala.js is backed by… you know… Scala and Kotlin is done by JetBrains. There is elephant in the room as well, and it is called TypeScript. Maybe next time.
You can find sources here or you can just use online demo
]]>On this picture you can see two separate trees (a forest):
It is quite clear that connecting 3 and 7 won’t form a cycle as vertex 7 has not been visited yet. The difference between edges 3-1 and 3-6 is not so obvious anymore. All of those vertices (nodes) are visited, but 3-1 will form a cycle, while 3-6 will not.
It would help if we knew which tree given node belongs to, as cycle is formed only when connecting two visited nodes from the same tree (3-1). When connecting visited nodes from different trees, we do not create a cycle, we just connect two trees forming new bigger tree (3-6).
Storing something like TreeId
on each node and updating it when trees are merged would theoretically work but would be quite slow. Imagine that we just added single edge connecting two trees, let’s call them A and B. What we would need to do now is to update all nodes from smaller tree (let’s say it is B) and tell them “you are tree A now”. Now let’s assume both trees have 1000000 vertices… oops.
We need a better data structure to store such sets and, fortunately, there is one. It is called disjoint-set (also known as union-find or merge-find set) and it serves exactly that purpose.
Disjoint-set organizes items into trees where every item has a parent. Two items belong to the same set when they have same parent.
Let’s start with set of items where no merges has been done so every item is in its own separate set:
Merging two items into set is about assigning one as a parent of the other one:
Now, the root 2 identifies the whole set so the question “Which set item 1 belongs to?” is answered by “It belongs to set 2“. You can also say: 2 is representative items for the whole set.
On the diagram below, we can see two sets: set 2 and set 5. Items 1, 2 and 3 belong to set 2, while items 4, 5, 6, 7 belong to set 5. Which items becomes a root in merging process is irrelevant although we will try to limit the height of the tree to reduce potential number of hops.
Merging sets works exactly as it was shown before but it will be clearer with the picture:
We are trying to merge set containing item 3 with set containing item 7. First we need to find roots of those items (2 and 5 respectively) and then make one the parent of the other one. For algorithm correctness it can be either of those roots, but for performance reasons we choose the root of the higher one as new root. It helps keeping the tree relatively flat, as attaching tree of height 2 to the root of tree of height 3 does not change overall height. If both trees are of equal height we choose one arbitrarily and increase the height of resulting tree. That’s exactly what happened on the picture above, when two trees of height 1 (single item is height 0) formed new tree of height 2 after being merged.
With little though experiment, we can show that minimal tree of height 0 is a single item and minimal tree of height 1 is two items. As height increases only when merging trees of the same height tree of height 2 has to have at least 4 item. Merging two trees of height 2 creates tree of height 3 with at least 8 items. I guess, you can spot the pattern: there is minimum of 2^h items in the tree of height h, therefore finding a root has a pessimistic complexity of O(logn). I emphasized the word pessimistic as usually it does much better.
Finding a root of element can be used to compress the path at same time. As item’s potentially distant root is found, its parent can be updated to point directly to this root therefore compressing the path.
While merging 3 and 8 on the picture below:
two things can be spotted:
Because of these two techniques union by rank and path compression amortized complexity is lower than O(logn). Wikipedia says:
These two techniques complement each other; applied together, the amortized time per operation is only O(a(n)), where a(n) is the inverse of the function n = f(x) = A(x,x), and A is the extremely fast-growing Ackermann function. Since a(n) is the inverse of this function, a(n) is less than 5 for all remotely practical values of n. Thus, the amortized running time per operation is effectively a small constant.
I actually love the “is less than 5 for all remotely practical values of n” part.
All items in set need two properties: parent
and rank
(or height
). There are two possible approaches: objects in set would need to implement some specific interface (T: IDisjointSetExtraInfo
) or we could maintain some internal dictionary Dictionary<T, ExtraInfo>
and store required extra information this way. As usual there are pros and cons of both approaches.
The approach with dictionary is more generic, so I’m going to use it, and allow any T
, with no constraints (apart from equality).
I’ve originally needed an implementation in Kotlin but as solution is quite generic I’ve also added an implementation in F# to my ever growing library-of-data-structures-which-I-may-want-to-use-in-F#-on-day (TM).
Let’s start with encapsulation of, mentioned before, “extra info”:
1 | // Kotlin |
1 | // F# |
(Completely off-topic: what F# compiler generates here is extremely puzzling, I understand it handles parent = this
but it still puzzles me. Check it with ILSpy if you dare)
So, we have extra info class (called Tag
), so far.
We can implement find
with path compression which is just following parent
link on the way up and updating it on the way back:
1 | // Kotlin |
1 | // F# |
Implementing merge
(or union
) is a little bit complicated, but just a little. We need to find
roots of both sets. If they are the same item, it means that objects are already in the same set therefore there is nothing to merge. If roots are different, they are in different sets, so we need to merge them by setting parent
property of one root to the other one, potentially updating height
(or rank
):
1 | // Kotlin |
1 | // F# |
Now, we can implement the translation layer between Tag
and T
, most likely a class encapsulating a dictionary:
1 | // Kotlin |
1 | // F# |
Find method, implemented before, makes sense only in a domain of tags which are not exposed outside this module/package. The value returned by find
is also not really worth keeping as it may change all the time while sets are merged. What we want to expose though is the function which will test if two items are in the same set.
There are two possible optimizations here:
T
s) are the same item (if (x == y) return true
)1 | // Kotlin |
1 | // F# |
The get
method in F# is a little wrapper for TryGetValue
. It wraps quite ugly Key -> 'Value byref -> bool
and converts it into much more functional 'Key -> 'Value option
.
We had merge already implemented, all we need is handling the translation between T
and Tag
:
1 | // Kotlin |
1 | // F# |
And again, we needed a little wrapper functions in F#. Sometimes .NET disappoints me with quite minimalistic API.
Regardless of my complaints, that’s it. Please mention disjoint-set when talking to your friends, maybe when discussing Ackermann function or generating mazes using Kruskal’s algorithm.
]]>So last week I was doing maze generator using randomizes depth first search with Fable. Then, to increase “branching factor” I’ve added stack shaking. Today it’s time for slightly different approach.
As I said before this task was just kind of excuse technologies which I never used before. So far, I managed to scratch the surface of Fable, Webpack and VirtualDOM. For performance reasons VirtualDOM got replaced by jCanvas.
So, today’s new tech is Scala.js! Yay! I’m a big fan of Scala although I did not have a chance to use it for anything bigger than HelloWorld so far. I’m not saying that this task is much bigger, but at least it does something. Anyway, Scala.js, here I come!
It was not trivial to set up the environment. I actually struggled with the environment for couple of days before I managed to make it run. Making it work with Webpack was painful, especially because I’m not proficient in either of those. Apparently, Scala.js does not produce modular JavaScript and expects everything to be in global
, so instead of:
1 | var jquery = require("jquery"); |
we need this:
1 | // not actual code! |
Quite nasty. Maybe there is easier way, but it wasn’t obvious. If you know how to do it better let me know, but if you have similar problem you can use my generic empty project, but be aware - is highly opinionated.
Let’s do some coding now…
Most of maze generation algorithms on Wikipedia are building spanning trees for graphs where vertices are representing rooms and edges are representing doors.
Last week’s approach was randomized depth first search now it’s time for Prim’s algorithm.
Prim’s algorithm is building minimum spanning tree. We don’t need minimum, we need random spanning tree (that’s what randomized depth first search was doing). To achieve that, we can assign random weights to edges so minimum spanning tree will actually become random spanning tree. I didn’t but it could be actually interesting to play with different random distributions.
Let’s start with modelling the Node
(or Vertex) and Edge
:
1 | trait Node[E] { |
If you don’t know what trait
is, you can think about this as interface
from Java or C#. It is a little bit more complicated than that, but it is good enough aproximation, at least for this model. So, Node
(vertex) has a sequence (list?) of edges going out, and Edge
has two nodes, beginning and end, plus weight. That’s what Prim’s algorithm needs to work.
Actually, Edge.weight
does not need to be modelled as Double
. It could be declared as type parameter, let’s say W
:
1 | trait Edge[N, W] { |
In such case implementation of Prim’s algorithm would need a way to compare two W
s (Ordering[W]
or IComparator<W>
) but, for simplicity, I’ve implemented it as Double
so let’s leave it like this.
So, let’s start with Prim’s solver:
1 | class Prim[N <: Node[E], E <: Edge[N]](val node: N) { |
So, what we have is a generic class which take two types N
and E
where N is Node of E and E is Edge of N. We are just making sure types are consistent.
How Prim’s algorithm work? It starts with a single node and marks it as visisted. On every step it choses an edge with minimum weight which connects visited node to not visited node.
That’s kind of it and it can be derived from the name: minimum spanning tree. We know that every node needs to be in solution (the word: spanning), we don’t take edges with both ends already visited as we don’t want cycles (the word: tree), we don’t take edges with both ends not visited as it could create disjoint graph (the word spanning again, and tree but not forest). We also take lightests edge available as we need it to be minimum. Don’t quote this though, it is not formal proof of correctness :)
So this description suggests the solution needs: set of visited nodes and ordered queue of edges.
1 | import scala.collection.{mutable => c} |
Nothing fancy. We have set of visited nodes (visited
), we have ordered queue of edges (queue
). To make it ordered we use PriorityQueue
provide a way to compare edges (ordering
) by comparing weights. As PriorityQueue
puts heaviest first we need to reverse it. I used -weight
but Ordering
has actually a method reverse
(I just found it out too late).
As I said last week I like one-liners to remove clutter from business code, so let’s define few for this task:
1 | private def test(node: N) = visited.contains(node) |
We can test
the node if it was visited, we can mark
the node as such, we dequeue
the edge from queue of lightests edges, and we can fanout
from given node by adding all outgoing edges to the queue of lightests edges. As last one we have full definition what a visit means, it is marking and then fanning out (I use this word wrongly, don’t I?).
Two non-trivial things. My reimplementation of deqeue
returns Option[E]
. I actually still don’t belive that there is no dequeue returning option on PriorirtyQueue
. I missed it, right? For those who don’t know what I’m whining about let me explain. In functional languages, and Scala claims to be one, exceptions are for trully exceptional situations like, “cosmic ray just hit the CPU”. The expected situations should be handled by type system, and dequeue
is perfect example of it: queue can be empty and when you try to get something from it the result should be “nada, come back later”. And that’s exactly what Option
type gives us.
The other thing (Am I digressing all the time?) is the splat operator (:_*
) in fanout
. I actually spent good 15 minutes looking for it as my google-foo failed me. Apparently, enqueue
takes multiple arguments (varargs
in Java or params
in C#) but all I had was a sequence (one argument). C# deals with that implicitly but Scala requires this… thing. I’m actually not sure what it is, maybe something like static cast in F# (:>
) with wilcard (_
) as a type? Anyway, it works as expected.
So we have mini language for domain of Prim’s algorithm. Let’s do the algorithm then. If it was about solving the problem I would use a for
loop (while
, foreach
whatever). If it was a language with lazy generators or coroutines I would reuse the for
loop with yield
, but Scala does not have lazy generators. I guess “yet”, as every language is getting them (JavaScript and Kotlin). Anyway, that’s why we need to store the state (visited
and queue
) as class members and not inside a generator function.
Let’s go:
1 | def next(): Option[E] = { |
So this method potentially returns next edge. Potentially as we may run out of edges and that’s the stop condition for algorithm. So it takes next edge (dequeue
) and if there are no more edges it just returns None
and that’s it (flatMap
). If there was an edge still available it tests both ends (test(edge.X)
). If both are already visited (true, true
) this edge is not good let’s take next
one. If only one of them is visited (true, false
and false, true
) mark visit
the unvisited one and return this edge (Some(edge)
). If both of them seems to be not visited yet something went horribly wrong (cosmic ray?) and it’s time to panic (throw
).
Nice.
We have generic Prim’s algorithm implemented so far but we need to use to solve very specific problem. Building a maze. So let’s deal with the domain.
Let’s start with Point
with geometric coordinates:
1 | case class Point(x: Int, y: Int) |
a Room
which is a Node
(has trait or implements interface) in a graph:
1 | class Room(val position: Point) extends Node[Door] { |
It additionally, defines add
method (I should have named it connect
I guess) which creates door connecting two rooms. I’m actually quite impressed how flexible scala is in this respect. Node
trait defines edges
as def edges: Seq[E]
(a method returning sequence) but Room
class implements it as val edges: ArrayBuffer[Door]
(a field holding mutable collection of Door
). No implicit interface implementation or shadowing was needed, it just worked.
The last one is Door
(or edge):
1 | class Door(val A: Room, val B: Room, val weight: Double) extends Edge[Room] |
The last thing we need for domain is the way to create the graph:
1 | class Model(size: Point, random: () => Double) { |
Model
object takes a size of the world and random number generator (so we can use any generator we want). It creates two dimensional array of rooms (Array.tabulate
) initializes it (new Room(x, y)
). If provides a function get room object at given location (at(...): Room
) and connect
two rooms. Both methods are kind of overkill but make the business logic (the for
loop) clutter-free. We also export starting room (room00
). If you really wanted to you could implement this Model
class as a single function: createModel: (Point, () => Double) => Room
, but old habits die hard.
So, once again, the domain is implemented. All what is left is the UI or presentation layer.
I won’t be describing UI in details, so please refer to Github for actual sources. In general it goes like this…
We have some constants:
1 | val WORLD_SIZE = Point(100, 100) |
defining size of the universe (WORLD_SIZE
), some colors, dimensions in pixels (DOOR_SIZE
and ROOM_SIZE
), and helper functions:
1 | def toPixel(v: Int): Int = v * ROOM_SIZE + (v + 1) * DOOR_SIZE |
to translate between room location to pixel position (toPixel
).
We need to intialize canvas:
1 | def initialize() = { |
by setting width
, height
and viewbox
, and attach restart
method as a handler for click
event on Restart button.
Restart shuts down previous animation (shutdown
), sets up the drawing context of the canvas (context
), initializes the model
and algorithm
and starts animation on interval (window.setInterval
).
1 | var handle: Option[Int] = None |
We will also need to actually draw rooms and doors:
1 | def drawRoom(context: CanvasRenderingContext2D, room: Room) = { |
The last part is the single step of animation, which takes algorithm
and drawing context
:
1 | def step(algorithm: Prim[Room, Door], context: CanvasRenderingContext2D) = { |
If next edge/door (algorithm.next()
) cannot be found (case None
) then animation is stopped (shutdown()
) otherwise it just draws door and two rooms.
And yet again: that’s it.
You can get your own copy from Github or you can just watch it working here
I really loved the fact that I had access to Scala collections and they worked as expected. It gives you this warm feeling when you can just use PriorirtyQueue
of the shelf. The code Scala.js produces is not nearly as readable as Fable gives us. Is actually pretty awful with horribly mangled names. That’s why I was struggling to understand why it does not see jQuery and how to make it work with Webpack. I do now, but it took me a while.
This blogpost requires familiarity with previous one.
One of the disadvantages of using DFS to build mazes is “low branching factor”. The problem is that it actually runs for long time before hitting dead-end and having to backtrack, so it creates very long corridors with no room to “make the wrong turn” for potential maze explorer.
Let’s deal with it.
Originally I used recursive version, but to avoid stack overflow, actual demo was done non-recursive version of DFS.
1 | let stackless mark test fanout node = seq { |
This version will be modified to allow “shaking the stack”. I’ll introduce one argument (shake
) and use shake stack
instead of just stack
in match statement.
1 | let stackless mark test fanout shake node = seq { // <-- here |
That’s absolutely it in “The algorithm” layer.
There was a “glue” layer adapting “The algorithm” to “The domain” and it just stopped working as we added new argument to the function. Don’t worry, though, it just a simple fix.
Previously it was calling traverse
(or stackless
depending which approach you used ‘elegant’ or ‘safe’) now it should call stackless
(as traverse
does not support shaking) with this extra argument. So the old code:
1 | InitAt (0, 0) |
should be changed to:
1 | InitAt (0, 0) |
and the code will compile again and work exactly as it was working before (you may remember that id
function does absolutely nothing). Why we did that then?
Because now, on every single step we have an ability to modify the backtracking stack.
I’ll suggest something like:
1 | let shake stack = |
Which in 99% of cases returns stack
unmodified but from time to time shuffles it completely. Of course, it would be nice to use it now (id
gets replaced by shake
):
1 | InitAt (0, 0) |
Please note, that from algorithm complexity point of view this is not good approach, as complexity just jumped from O(N) to O(N^2) (it’s a little but more complicated than that), but definitely it gives better results, as it tries to branch earlier.
The bottom line is that I did not really modify the algorithm (DFS) I just injected some extra behavior into it, but it is totally externally controlled (kind of definition of “injected”, right?). Functional composition rlz.
]]>For quite some time I was looking for an excuse to use Fable. Fable is F# to JavaScript compiler. I generally shy away from JavaScript, as I am biased towards backend but as a big fan of F# I wanted to play a little with Fable (and Scala.js actually). On top of that, I wanted to try some other technologies I’ve never used before: VirtualDom (maybe React), Webpack, Pixi.js. All I needed was an excuse…
I’ve found Redgate’s first ever coding challenge on LinkedIn and I decided to do it with Fable in the browser. The challenge is about writing an application to generate mazes (thus the Daedalus reference). I wasn’t going to apply as my solution is probably the most trivial one using “randomized DFS”, so there is nothing to show off, but, I wanted to use those tools.
EDIT: eventually, it did apply
Initially solution was building SVG with VirtualDOM. It was very neat as Fable/VirtualDOM uses Elm architecture (check Fable samples page). It was fast enough to solve the problem but unfortunatelly, for bigger mazes (>50x50), not fast enough for live animation. Changing multiple <rect>
to one long multipart <path>
made it a little bit faster (~20%) but it still wasn’t good enough and it was definitely slowing down further it went.
The final version is not as ambitious, uses jQuery and jCanvas. Presentation layer is very old school, but it works and is very fast (relatively speaking, of course). Note, I could deal with the <canvas>
without any supporting libraries, but one of my goals was to investigate and evaluate integration with native JavaScript libraries as, in my opinion, integration is one of the most important aspects of any X-to-JavaScript transpiler.
Scott Wlaschin says “No abstraction is too small”. I agree, I’m a big fan of “extracting abstraction” and I’m so glad F# supports and encourages local one-liners. I believe problems should be decomposed into small managable chunks first and then composed back into solution. Things should be named appropriately as well. Let me use example given by Kevlin Henney (it’s actually Dan North’s example but I have no link):
1 | if (portfolioIdsByTraderId.get(trader.getId()).containsKey(portfolio.getId())) { |
Even if we understand every single word in this statement, it is still unclear what purpose it serves. It is not abstract enough, it contains too much of “implementation”. Maybe we should consider this as an alternative:
1 | if (trader.canView(portfolio)) { |
Yup, that’s much better.
For every solution, at some point there will be a need for some “ugly implementation details”. It is just nicer when you can push it far away from business logic so it does not get in a way when you try to reason about what this code “actually does”.
In this article I will use a some one-liners. They might seem like overkill for this task but this is primarily fun project and using them is fun!
There are few algorithms listed on Wikipedia and randomized depth-first search is probably the simplest one.
It has two disadvantages:
I’m going to decompose the solution into smaller pieces instead of using single monolithic function.
A physicist and a mathematician setting in a faculty lounge. Suddenly, the coffee machine catches on fire. The physicist grabs a bucket and leaps towards the sink, fills the bucket with water and puts out the fire. The second day, the same two sit in the same lounge. Again, the coffee machine catches on fire. This time, the mathematician stands up, gets a bucket, hands the bucket to the physicist, thus reducing the problem to a previously solved one.
Let’s start with generic depth-first search then:
1 | module DFS = |
where mark: 'T -> unit
is the function which will take a node and mark it as visited, test: 'T -> bool
will test is node has been visisted already, fanout: 'T -> 'T seq
will take a node and return a sequence of connected nodes (neighbours?) and finally node: 'T
is just a starting point.
The algorithm goes like this:
node |> test
) mark it as visisted (apply mark
) and return it (yield
). node |> fanout
), rinse and repeat (Seq.collect traverse mark test fanout
)If you don’t know what apply
does I would recommend my other post.
Done. We can go home… OK, I’m just joking.
NOTE: This solution is vulnerable to stack overflow as it goes deeper and deeper with every visited node. The actual solution uses different implementation of DFS which is using while
loop and lists to simulate call stack (I called it stackless
which is a little self contradicting, isn’t it?). Idea is absolutely the same though, but code is less elegant.
So, we have an algorithms. Now we need domain model.
Initially, the domain of this problem consisted of the World
, which is a collection of Rooms
which in turn have their Location
and are connected (or not) through Exits
. Not all of those concepts are needed for the algorithm. They may or may not be needed by presentation layer but we probably shouldn’t jump ahead, I guess.
So, let’s start with Location
(x and y coordinates) and Direction
(north, east, etc…):
1 | type Location = int * int |
There is also a relation between directions (opposite
) and a function allowing to move from one location in given direction (shift
).
1 | let opposite direction = // Direction -> Direction |
Traversing a maze is about actions (or moves). Theoretically, we could model it with single type of action (move south from 5,4 to 5,5), but first move (which is start at 0,0) does not have source nor direction and with language like F# you should not compromise on domain model aka make illegal state unrepresentable.
So, I ended up with two possible actions: teleporting to starting location and moving from one location to another:
1 | type Action = |
The Action
has it’s “property” called target, the Location
where it ends:
1 | // Action -> Location |
It is important to realize, that DFS in this case does not really traverse rooms (graph nodes), it actually traverses actions (graph edges), although it is the room which is visted (not action).
Long story short, there is some glue needed between “The algorithm” and “The domain” presented above.
Let’s start with some one-liners for solution:
1 | // int -> int -> Action seq |
NOTE: HashSet
in Fable is modelled using JavaScript Set
which does not use structural equality (I learnt it the hard way). Therefore two identical tuples would not be recognised as such. We need to encode
tuple value as something which is properly handled by Set
. Encoding tuple as single int
is one options, encoding it as string
would be also valid (but a little but slower, I suppose).
We have function to test is given location is valid for given maze size (isValid
), we can test if action points to a room which has been visisted before (test
) and mark the location as visisted if needed (mark
). That is just a small vocabulary for our problem.
It’s time to define fanout
method which will return all valid the neighbours:
1 | // Location -> Action seq |
As you can see, it takes a source location, then generates a sequence of MoveTo
actions in every direction and then eliminates the ones with invalid target locations (the ones which would point outside the maze). You may wonder why fanout
returns candidates in pretty deterministic order. And that’s fair question. I just don’t think randomization stategy is responsibility of fanout
function, I think we can postpone this decision (at least for 5 more seconds).
We have all building blocks ready now and it’s time to call DFS.traverse
(or DFS.stackless
). As I said before traverse
operate on actions (not locations), and functions we defined so far work on locations. We will need some adapters, and some randomization of fanout
output.
Functional composition to the rescue:
1 | InitAt (0, 0) |
It starts with action (InitAt (0, 0)
), and uses composition to adapt input argument of mark
, test
and fanout
. It also randomizes the output of fanout
with shuffle
.
And this sequence of actions it the result of buildMaze
.
Done, again. OK, we need presentation.
Without getting into much details we need a <button>
and a <canvas>
:
1 | <button id="restart" type="button" class="btn">Restart</button> |
That’s the UI. Right? Yeah, kind of. Be aware that the code here is for illustration only, please refer to github for actual working sources.
Let’s start with importing native JavaScript libraries:
1 | let jq = importDefault<obj> "jquery" |
As you can see there a little bit weird syntax when accessing arbitrary JavaScript objects. The good news is you can import TypeScript .d.ts
definition files into Fable to have strongly typed interfaces. In this case though, I used so little of it, that I could manage dynamic invocation.
Long story short, importDefault
get’s translated into require
(for CommonJS
). The $
operator is invoke, ?
operator is get and <-
is set. $
operator in many cases can be ommited.
So, a ? b ? c(77)
would be translated to a.b.c(77);
while a ? b ? c <- 11
would be translated to a.b.c = 11;
.
Please note, that as there is an assumptions that everything returns obj
(or obj -> obj
which is also an obj
). F# does not like dangling result values so you need to ignore
results you don’t care about. I definitely recommend referring to Fable website for more details.
Let’s define some constants:
1 | let WORLD_WIDTH = 100 |
and a simple function to convert world location to coordinates in pixels:
1 | let toPixel (x, y) = // Location -> (int * int) // and yes, I'm cheting with types a little |
Let’s set the <canvas>
up, by setting width
, height
, viewbox
and viewport
(using jQuery):
1 | let w, h = toPixel (WORLD_WIDTH, WORLD_HEIGHT) |
and wire click
event on “Restart” button:
1 | let mutable cancel = id |
The thing with cancel
might be a little bit unclear. Function startAnimation
will return a function (function returning function, yes) which can be called to cancel animation. So next time Restart
button is pressed previous animation will be cancelled before starting new one. To avoid null
(or None
) checking (on first run) cancel
just gets initialized with function which does nothing (yes, id
is a function which does nothing).
Back to solution, when button is pressed potential old animation is cancelled (cancel()
), canvas is cleared (canvas ? clearCanvas () |> ignore
) and new animation is started (cancel <- startAnimation canvas
).
There is only one method left, then:
1 | let startAnimation canvas = // ... |
Please note, the code below in the scope of startAnimation
.
We will definitely need to draw rectangles on canvas, and that’s kind of all we are going to do. I will use jCanvas
to do this, but it is an overkill, of course, it could (and should?) be done with browser API, but I’m exploring here, right?
As with dynamic invocation eveything is obj
we want to add some types when JavaScript and Fable meets. Let’s wrap jCanvas.drawRect
first into drawBox
function:
1 | let drawBox (color: string) (x: int) (y: int) (w: int) (h: int) = |
Yup. Done. Not pretty but done. We can forget about this traumatic experience now. It actually generates quite readable code:
1 | var rect = { |
From now on, we can forget about JavaScript interop again. We can just use drawBox
and implement drawRoom
to draw a room, and drawDoor
to draw a door:
1 | // Location -> unit |
Room
is drawn as big square, while Door
is just a slim rectangle (depends on relation between DOOR_SIZE
and ROOM_SIZE
). As you can see doors have different shape depending on direction (for example: North vs East).
Now, we need to start traversing the maze:
1 | let mutable action = buildMaze WORLD_WIDTH WORLD_HEIGHT |> Enumerator.create |
You can notice Enumerator
here, which might be a little bit cryptic but it just provides slighlty more F#-ish way to use IEnumerable<T>
interface.
The last part is the animation loop, we need to draw actions as they come. Let’s schedule a callback every 1/60th of a second (should I use requestAnimationFrame
here?) which will take current frame (well… action), draw adequate objects (drawRoom
and drawDoor
) and then proceed to next action (action <- action |> Option.bind Enumerator.next
):
1 | let mutable cancel = id |
The last line returns cancel
(returns a function, but does not call it) from startAnimation
so animation can be externally cancelled.
Note: Time.interval
is just a wrapper for setInterval
and clearInterval
to have more F#-ish experience:
1 | module Time = |
I guess that’s it.
You can find solution on github. It actually has many branches as I was trying many approaches. I started with “Immutable domain with VirtualDOM to generate SVG”, then I switched to “Mutable domain with VirtualDOM to generate SVG paths”, then I switched to “Mutable domain with jCanvas” and then I realized that half of domain was actually needed by VirtualDOM approach only. So, last incarnation if Daedalus is “Mutable mini domain with jCanvas”.
If you want to just see it work, you can find it here
As mentioned DFS has a problem with low branching factor. I’ll try to address the problem in next blogpost.
apply
after Kotlin (damn you, Kotlin!) wasn’t the most preferred option by the public. I did like apple |> apply eat
semantics but if Scott Wlaschin says apply
is a different thing then it is a different thing. To be precise Scott’s is apply: (a -> b) -> a -> b
and mine was (emphasize on was) apply: (a -> unit) -> a -> a
. Apparently, the function which does whatever I wanted apply
to do is called tee
(after Unix command) or tap
(at least in Ruby and Ramda.js).So I’ve edited it and replaced apply
with tap
, but essentially it is almost unchanged… Let’s go then.
One of everyone’s favourite features of F# is pipe (|>
) operator. It allows to pipe output of one function as input to another function preserving visual honesty. The general idea is that, in English, we read left-to-right and top-down. In C# (C, C++, Java, Pascal, Python) we read in all possible directions, most likely top-down for overall structure but botton-up and right-to-left for single statements.
For example:
1 | var y = Math.Round(Math.Exp(Math.Sin(x*5.2 + 7.1))); |
starts at the right end going left-to-right for a moment (x*5.2 + 7.1
) but then turns right-to-left with Math.Sin
, Math.Exp
and finally Math.Round
(in this order). In F# the pipe operator (|>
) allows to write code exactly in the same order as it is going to be executed:
1 | let y = x*5.2 + 7.1 |> Math.Sin |> Math.Exp |> Math.Round |
Around the world, many hours have been spent arranging function arguments (guilty!) to allow such seamless experience. But sometimes, the universe is against us. Let’s assume we would like to print out the value after Math.Sin
. The conservative approach would be quite intrusive - we would need to break expression in half:
1 | let temp = x*5.2 + 7.1 |> Math.Sin |
Whoa! That is intrusive.
But here comes the rescue. The tap
function implemented as:
1 | let tap func arg = func arg; arg |
The function itself is trivial, it takes a function and an argument, executes given function with given argument but then returns it, so the argument goes through the function:
1 | let y = x*5.2 + 7.1 |> Math.Sin |> tap (printf "%g") |> Math.Exp |> Math.Round |
In the example above, the value passed between Math.Sin
and Math.Exp
has been redirected “for a moment” to printf "%g"
without any temporary variables or breaking the flow.
Some say, you tap into the computation stream, maybe that’s a good way to think about it.
Recently I needed to shuffle an array. The algorithm I used shuffles array in place:
1 | let inline swapInPlace i j (array: 'a[]) = |
(Random.randomInt
is not a standard function, but its implementation is irrelevant for this example)
I needed it as pure function, which will not mutate input array, just return shuffled version of it. Let’s do it:
1 | let shuffle array = |
Maybe we can do better with tap
? Yes, we can:
1 | let shuffle array = array |> Array.copy |> tap shuffleInPlace |
Much better.
So, use tap and carry on!
]]>Once upon the time I needed to implement state machine. To not reinvent the wheel I reviewed what’s available: Windows Workflow Foundation, Appccelerate.StateMachine, bbv.Common.StateMachine, Stateless, SimpleStateMachine, Solid.State, and StateMachineToolkit. Windows Workflow Foundation was just scary, apart from the fact that State Machine is not available in .NET 4.0. It didn’t look lightweight either.
None of the others satisfied my requirements either:
KeyPressed
should also carry information which key has been actually pressed;EnteringText
) should be able to hold a list of keys pressed so far;KeyPressed
event may cause transition to different state depending which key has been pressed;I’ve implemented it in C#, and I’m relatively happy with it, and you can find it on GitHub. As an exercise I implemented it for Kotlin as well, also on GitHub. Then I had to implement one for work, in Java this time.
I decided that maybe it’s time to do something for F# community, and implement nice functional State Machine Construction Kit. I dropped the “transition rules should be implemented outside states” requirement as it was adding some messy reflection code.
To make it more F#y and functional I started with fundamental question: what is the state
? What is its essence?
It is actually a function which will take an event
and produce new state:
1 | type State<'Event> = 'Event -> State<'Event> |
This would actually not compile, because it would create infinite recursive type alias, but:
1 | type State<'Event> = | State of ('Event -> State) |
will do just fine.
Actually it would be a little but nicer if it would be possible to return State option
to handle termination:
1 | type State<'Event> = | State of ('Event -> State option) |
…but, I decided to make it rather with explicit state case:
1 | type State<'Event> = |
So we have transitive state (Next
for State (Some state)
) and terminal state (Stop
for State None
).
Please note, that we could add more cases, for example:
1 | type State<'Event, 'Result> = |
but this would introduce some complexity which I don’t want in this example, but you are more than welcome to introduce yourself.
So, let’s go back to my State Machine Construction Kit. We already have a state but we also need a function to fire events and transition from state to state, let’s call it feed
, we feed a state with event. It’s actually almost done as state is a transition function:
1 | let feed state event = |
For this example I will use some trivial state machine handling opening and closing doors:
So we have Open
and Close
events:
1 | type Event = | Open | Close |
…and have two states: opened
and closed
. The states themselves are functions which take events and produce new states:
1 | let rec opened event = |
Let’s define an initial state, a let’s say it is closed
:
1 | let mutable state = Next closed |
Now we can send Open
event to it and store new state:
1 | state <- Open |> feed state |
Ta-dah! Done.
Please note, that to handle sequence of events easily, the only thing you need to is to use fold
:
1 | events |> Seq.fold feed state |
For my personal use I actually created a class to encapsulate mutability. It is, of course, still there but hidden:
1 | type StateMachine<'Event>(initial: State<'Event>) = |
What about context (data shared by all states) and state’s state (state internal data) you might ask? By the power of closures and currying there is nothing special to implement. For example, let’s imagine a door state machine which makes sounds (with injected sound emitter) and can be locked or unlocked when closed (state’s internal data):
1 | type Event = | Open | Close | Lock | Unlock |
Note, there is a sound
function passed and all states have access to it and this is your context. Additionally closed
state has a locked
‘property’ and behaves differently depending on the value is this property (cannot be opened when closed, and needs to be unlocked first). You can call it substate if you want.
What if I don’t like mutable variables and I want my state machine to be an actor / agent? Let’s just wrap it:
1 | let createAgent initial = |
So, the full module, already a little bit bloated with helper functions, is:
1 | module StateMachine = |
I can run this now with:
1 | let agent = printfn "%s" |> configureDoor |> StateMachine.createAgent |
I have to admit. I failed. There is no such thing as State Machine Construction Kit for F#, at least not the one worth releasing, in short, there is just a function:
1 | type StateMachineConstructionKit = 'State -> 'Event -> 'State |
but I just can’t put it on GitHub. Maybe gist?
]]>Anyway, solutions which got most votes in both categories, best practice and clever use:
1 | bool IsPerfectSquare(long number) { |
This is kind of clever, as .NET (surprisingly) does not provide double Math.Frac(double)
, which would need to be implemented as:
1 | double Frac(double number) { |
But is it correct (best practice) at all?
Every time you see equals (==
) used with floating point types the red light should go off in your head. Equality and floating point numbers do not work well together. Floating point numbers are usually greater (or equal) than (>
or >=
), less (or equal) than (<
or <=
), or within particular range (Math.Abs(x - y) <= Epsilon
), but they are rarely equal (==
). At least you should not rely on that.
Just try that:
1 | var sum = 0.0; |
So I know that clever implementation of IsPerfectSquare
is potentially flawed, but as a true wannabe skeptic, I also know that experiment beats theory. I decided to find what is the smallest not so perfect square number which will deceive this method and force it to provide false positive.
The best bet is a number which is true perfect square plus 1, so:
1 | static bool IsPerfectSquare(long number) { |
…and we have an answer in below 3s:
1 | 4503599627370497 is the smallest fake perfect square |
which is 67108864^2 + 1
.
How can we implement IsPerfectSquare
properly then?
For square roots in integer domain we should probably use dedicated algorithm but because this is outside of the scope here (and outside the scope of this kata, I suppose) we need to think how to make Math.Sqrt(...)
work for us.
We need to bring the equality test back to integer domain. So, even if we use floating point numbers to calculate square root, we will perform the test itself using integers.
Let’s get the integer (rounded) “square root candidate” first:
1 | var root = (long)Math.Sqrt(number); |
…and then test if it is really is a square root of given number:
1 | return root*root == number; |
That’s it. Not much more code. There was really no reason to sacrifice correctness for “cleverness”.
1 | bool IsPerfectSquare(long number) { |
As a bonus we can also check if rounding might be a problem leading to false negatives:
1 | var max = (long)int.MaxValue; |
…and it (most likely) won’t.
Of course, this approach will stop working at some point:
1 | var number = new BigInteger(long.MaxValue); |
…but that’s different story.
]]>