HiveBrain v1.2.0
Get Started
← Back to all entries
patternMinor

Refactoring while-do into tail recursion with F#

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
refactoringwhilerecursionwithintotail

Problem

I have a while-do loop nested inside a while-do loop in my program, due to it needing to iterate in two dimensions through an array of arrays, and originally my loop looked like this:

while ( tHeightIndex < tSearchHeight - 1 ) && tContinue do
    while ( tWidthIndex < tSearchWidth - 1 ) && tContinue do
        let tCurrentValue = tLargeArray.[tHeightIndex].[tWidthIndex]
        if tCurrentValue = tFirstSmallPixel then
            tMatch <- ArrayFunctions.SearchSubset tSmallArray tLargeArray ( tHeightIndex, tWidthIndex )
            if tMatch then tContinue <- false
        if tMatch = false && tContinue = true then
            tWidthIndex <- tWidthIndex + 1
    if tMatch = false && tContinue = true then
        tWidthIndex  <- 0                       // Reset to search next row
        tHeightIndex <- tHeightIndex + 1
tMatch, tWidthIndex, tHeightIndex


However, seeing as I'm doing this project entirely to learn better functional programming practices, I refactored that nested loop into two tail-recursive functions. This code passes my unit tests and appears to work correctly, so I would like advice about the style of the code and whether there's better ways I can make the code read clearly.

The relevant part to the original while-do loop is located after the declaration of firstSmallPixel.

```
module ImageSearch =
open ImageFunctions

let SearchBitmap (smallBitmap:Bitmap) (largeBitmap:Bitmap) =
let smallArray = Transform2D let foundImage = ArrayFunctions.SearchSubset smallArray largeArray ( heightIndex, widthIndex )
if foundImage then widthIndex , foundImage
else ContinueLoop ()
| ( true , false ) -> ContinueLoop ()
| ( false, _ ) -> widthIndex , false
WidthLoopRec heightIndex 0

let HeightLoop () =
let rec HeightLoopRec heightIndex =
let widthIndex, foundImage = WidthLoop

Solution

I think that learning functional programming should be about making your code more readable (and also better in other aspects), neither of your samples seems very readable to me.

I also think that when working with collections in functional programming, the most important concept is not recursion, it's higher-order functions.

If you use those in the form of a query expression, your code could look like this:

query {
    for row in 0..searchHeight do
    for col in 0..searchWidth do
    let pixel = largeArray.[row].[col]
    where (pixel = firstSmallPixel)
    select (row, col, pixel)
    head
}


The nice thing about this code is not only that it's more readable and shorter, it's that it emphasizes what you want to do, not how to do it.

Code Snippets

query {
    for row in 0..searchHeight do
    for col in 0..searchWidth do
    let pixel = largeArray.[row].[col]
    where (pixel = firstSmallPixel)
    select (row, col, pixel)
    head
}

Context

StackExchange Code Review Q#59293, answer score: 2

Revisions (0)

No revisions yet.