Worice
Worice

Reputation: 4037

Functional increment

I am working on a simple function that should, given x, return a tuple (y, z) such that y <= abs(5) + z * 10 = x, where z the smallest possible value.

In C, I would loop over z++ and y++, until their sum matches x.

Currently, I am trying to solve this problem functionally. Please consider the following example:

let foo x =
    let rec aux (y, z, q) =
        match (y + z * 10) with
        q       -> (y, z)
        |_      -> aux(y + 1, z + 1, q)    //How to correctly set the increments?
     aux(0, 0, x)

This approach always returns (0, 0), no matter what. I referred to this question, while thinking a solution. I am aware that mutable variables should be avoided, and that is what I do. Unfortunately, I am afraid I missed the point, somewhere, thus I am approaching the problem from the wrong side.

Upvotes: 2

Views: 309

Answers (2)

TheQuickBrownFox
TheQuickBrownFox

Reputation: 10624

In F# you are generally either within a value expression or a pattern matching expression. When you do this:

match (y + z * 10) with
q       -> (y, z)

You're effectively saying: "Calculate y + z * 10 and then always assign the result to a new variable q, ignore this new variable and return (y, z)". This is because q is written in a pattern matching expression as it's just after with.

This is also why you're getting a warning on the next line saying "This rule will never by matched". This is a very common misunderstanding when people are learning F#.

You're not really making use of pattern matching at all when you do this. So I would recommend using an if expression instead:

        if y + z * 10 = q
        then (y, z)
        else aux (y + 1, z + 1, q)

This is actually equivalent to using the ternary operators ? and : in C because it's an expression, not a statement, but it reads more clearly.

Upvotes: 1

scrwtp
scrwtp

Reputation: 13577

You're introducing a new q binding for the result of the expression evaluated in your first case match rather than comparing against it. What you want is something like this:

match (y + z * 10) with
| r when r = q -> (y, z)
| _ -> aux(y + 1, z + 1, q)

Upvotes: 4

Related Questions