Reputation: 179
I'm trying to make a function that compares a tuple with the values of an array of tuples. I need this to return a boolean, but VS2013 keeps telling me: "This expression was expected to have type 'unit', but has type 'bool'"
let compare (i,j,a,(x : (int*int*int) array)) =
for q in 0 .. x.GetLength(0) do
match (i,j,a,x) with
| (i,j,a,x) when (i,j,a) = x.[q] -> true
| _ -> false
Also tried to give the values as two parameters, but it doesn't work either:
let compare (i,j,a) (x : (int*int*int) array) =
for q in 0 .. x.GetLength(0) do
match (i,j,a) with
| x.[q] -> true
| _ -> false
Any help would be appreciated!
Upvotes: 2
Views: 7772
Reputation: 243096
To expand a little bit on the answer from Chris, the main reason why your code does not work is that F# is an expression-based language and does not have imperative-style control-flow that you might be expecting here (if you incorrectly read the body of the expression as return
keyword).
As F# is expression-based, everything is an expression that evaluates to a value. So, true
is an expression that evaluates to true (boolean). Pattern matching from your example:
match (i,j,a,x) with
| (i,j,a,x) when (i,j,a) = x.[q] -> true
| _ -> false
... is also an expression that evaluates to true
or false
(boolean value) depending on the values of variables. In this case, conditional would be simpler though:
if (i,j,a,x) = x.[q] then true else false
... or you could just write the condition (i,j,a,x) = x.[q]
which means exactly the same thing. Now, for
loop is tricky, because it evaluates the body multiple times and so it would potentially get multiple return values. For this reason, F# has a special type unit
(think void
in C#) which represents a value that does not carry any information. So, for
loop expects unit
-returning body like:
for i in 1 .. 10 do
printfn "Foo"
You can check that printfn "Foo"
actually returns unit value by writing for example:
for i in 1 .. 10 do
let nothing = printfn "Foo"
nothing
If you place mouse pointer over nothing
, you'll see that it is of type unit
.
So, for
loop is not a good approach if you want to break the iteration in the middle (because it cannot be done in F#). As already mentioned by Chris and Søren you can use functions from the Array
module to easily implement the logic. Alternatively, you would have to write this using recursion or mutable variables - but the Array
module works nicely here.
Upvotes: 7
Reputation: 5688
Short and sweet:
let compare triple x = Array.exists ((=) triple) x
No need to unpack the tuple (i, j, x)
.
The notation (=)
turns the equality comparison operator into a function of two curried arguments. When we partially apply (=)
to triple
, that is, when we write
(=) triple
we get the function which takes one argument, and compares that argument to triple
, returning true or false.
Upvotes: 3
Reputation: 3769
The problem is the for
loop expects the expression within it to evaluate to unit
. You will need a different approach, for example using Array.exists
Upvotes: 2