The line before the else statement apparently was expecting a unit but got a boolean instead. I'm just starting out with F# but can't fathom this one.
I'm fighting the layout a bit as I've never used Stackoverflow before and the code box is still confusing me! The spacing in the original is indented, I believe, correctly.
let m = Dictionary<int, int>()
let rec fib i =
match i with
| 1 -> i
| 0 -> i
| _ ->
if m.ContainsKey(i) then
if m.[i] > 0 then
m.[i]
else
let x = fib(i - 1) + fib(i - 2)
m.Add(i, x)
m.[i]
If anyone can tell me how to keep the spacing in these posts I'd be grateful!
The last bit is slightly wrong - should be
if m.ContainsKey(i) then
if m.[i] > 0 then
m.[i]
else
let x = fib(i - 1) + fib(i - 2)
m.Add(i, x)
x
You are returning from within the if statement. You probably dont need the if m.[i] > 0 either. In this case you get
let m = Dictionary<int, int>()
let rec fib i =
match i with
| 1 -> i
| 0 -> i
| _ ->
if m.ContainsKey(i) then
m.[i]
else
let x = fib(i - 1) + fib(i - 2)
m.Add(i, x)
m.[i]
For formatting on Stackoverflow just paste the code in then highlight and press ctrl+k or hit the {} button to automatically put the section into code mode (code is indented four spaces past normal text)
Easy mistake to make if you're new to such kinds of languages. Keep in mind that F# is expression based, therefore an if-then-else clause is an expression that evaluates to something. In order for this to happen, the type checker requires all branches of an if expression to be of the same type, as with pattern matching. Moreover, if expressions missing a closing else branch are only valid if their branches are of type unit.
Keeping those things in mind, you can see that this snippet will not pass type checking on account of two reasons:
The nested if expression has branches that produce values of different types (namely int and unit) and
The outer if expression expects the inner one to have type unit.
Hope this helps :)
Related
I am teaching myself a bit of F# by doing a bit of simple matrix mathematics. I decided to write a set of simple functions for combining two matrices as I thought that this would be a good way of learning list comprehensions. However when I compile it my unit tests produce a type mismatch exception.
//return a column from the matrix as a list
let getColumn(matrix: list<list<double>>, column:int) =
[for row in matrix do yield row.Item(column)]
//return a row from the matrix as a list
let getRow(matrix: list<list<double>>, column:int) =
matrix.Item(column)
//find the minimum width of the matrices in order to avoid index out of range exceptions
let minWidth(matrix1: list<list<double>>,matrix2: list<list<double>>) =
let width1 = [for row in matrix1 do yield row.Length] |> List.min
let width2 = [for row in matrix2 do yield row.Length] |> List.min
if width1 > width2 then width2 else width1
//find the minimum height of the matrices in order to avoid index out of range exceptions
let minHeight(matrix1: list<list<double>>,matrix2: list<list<double>>) =
let height1 = matrix1.Length
let height2 = matrix2.Length
if height1 > height2 then height2 else height1
//combine the two matrices
let concat(matrix1: list<list<double>>,matrix2: list<list<double>>) =
let width = minWidth(matrix1, matrix2)
let height = minHeight(matrix1, matrix2)
[for y in 0 .. height do yield [for x in 0 .. width do yield (List.fold2 (fun acc a b -> acc + (a*b)), getRow(matrix1, y), getColumn(matrix2, x))]]
I was expecting the function to return a list of lists of type
double list list
However what it actually returns looks more like some kind of lambda expression
((int -> int list -> int list -> int) * double list * double list) list list
Can somebody tell me what is being returned, and how to force it to be evaluated into the list of lists that I originally expected?
There's a short answer and a long answer to your question.
The short answer
The short version is that F# functions (like List.fold2) take multiple parameters not with commas the way you think they do, but with spaces in between. I.e., you should NOT call List.fold2 like this:
List.fold2 (function, list1, list2)
but rather like this:
List.fold2 function list1 list2
Now, if you just remove the commas in your List.fold2 call, you'll see that the compiler complains about your getRow(matrix1, y) call, and tells you to put parentheses around them. (And the outer pair of parentheses around List.fold2 isn't actually needed). So this:
(List.fold2 (fun acc a b -> acc + (a*b)), getRow(matrix1, y), getColumn(matrix2, x))
Needs to turn into this:
List.fold2 (fun acc a b -> acc + (a*b)) (getRow(matrix1, y)) (getColumn(matrix2, x))
The long answer
The way F# functions take multiple parameters is actually very different from most other languages such as C#. In fact, all F# functions take exactly one parameter! "But wait," you're probably thinking right now, "you just now showed me the syntax for F# functions taking multiple parameters!" Yes, I did. What's going on under the hood is a combination of currying and partial application. I'd write a long explanation, but Scott Wlaschin has already written one, that's much better than I could have written, so I'll just point you to the https://fsharpforfunandprofit.com/series/thinking-functionally.html series to help you understand what's going on here. (The sections on currying and partial application are the ones you want, but I'd recommend reading the series in order because the later parts build on concepts introduced in earlier parts).
And yes, this "long" answer appears shorter than the "short" answer, but if you go read that series (and then the rest of Scott Wlaschin's excellent site), you'll find that it's much longer than the short answer. :-)
If you have more questions, I'll be happy to try to explain.
Disclaimer/edit: this is a fairly simple question, but I'm asking it since I'm (still) often confused by evaluation order in F#, esp. with respect to newlines vs. spaces. Trial and error always gets me where I want to, but I don't think you can really understand a language if you have to resort to trial and error.
If I write:
let res x =
x * 1 = x
|> ignore
all's fine, but if I write:
let res x =
x * 1 = x && x * -1 = -x
|> ignore
then the compiler complains (it says it expects bool -> bool, not bool -> unit). I would have expected the newline to act as a separator here.
Adding parentheses helps, and putting it on one line shows that it is evaluated as (X && (Y |> Z)), where X and Y are boolean expressions and Z is any function.
Is this true? And is there a simpler way to find this out? Or better, when is whitespace a significant operator and when not?
To give another example:
let v = x |> fun x -> float x |> fun y -> true
Why is y here of type float and not of type int -> float? This may be obvious, and I sure have programmed thousands of lines that way, it even feels natural, but why?
If the only answer to give is "operator precedence and -> comes before |>", so be it. But I guess/hope there's some more academical or otherwise formal though behind all this (and I still find it odd that && has lower prio than |>, again, I don't understand why and in that case it feels counter-intuitive).
Looking at https://learn.microsoft.com/en-us/dotnet/articles/fsharp/language-reference/symbol-and-operator-reference/#operator-precedence it seems that && has higher precedence than |> so your guess is correct and you need to add parenthesis:
let res x =
(x * 1 = x && x * -1 = -x)
|> ignore
It looks like a new line doesn't act as a separator unless it has a let binding or fall in one of the rules listed here
For example if you take this expression:
let res =
5 + 1
.GetType()
You also get an error, because it applies the . operator to 1 not to the whole expression, so the precedence rules still holds, regardless of the newline.
Ok, Ok - I know this is a bad idea in general. Nevertheless in a very specific context - Within my test cases I just expect a certain result and anything else would be an error in any way. And doing pattern matching simply obscures my test code.
Here an example
type Result =
| Success of int * int
| Error of String
let someFunc x : Result = // implementation not important here
// and then later in my test code
[<Test>]
member me.``Some Cool Test Method``() =
let (Success x, y) = someFunc "Foo"
equals x 1
equals y 2
Any ideas on how to make that more pleasant and compiler friendly?
Why don't you just write the test like this?
[<Test>]
member me.``Some Cool Test Method``() =
let actual = someFunc "Foo"
let expected = Success(1, 2)
equals expected actual
This doesn't generate any warnings that you'll need to suppress.
You can disable the warning by inserting this line somewhere before the incomplete pattern-match:
#nowarn "0025"
I used this before also for some quick tests, most likely the scenario you describe.
The other option which is probably the one you refer by doing pattern matching is to catch-all other cases with the wildcard _ and throw an error:
[<Test>]
member me.``Some Cool Test Method``() =
match someFunc "Foo" with
| (Success x, y) ->
equals x 1
equals y 2
| _ -> failwith "unexpected value"
then the compiler will be happy and if you know it will never reach there you don't care to handle that error further because you know it will never be thrown.
I have this simple F# function:
let compareNum x =
let y = 10
match x with
| _ when x = y -> 0
| _ when x > y -> 1
| _ when x < y -> -1
However, F# compiler gives me "Incomplete pattern matches on this expression" warning. In this case, all cases should cover every pattern.
I also see a similar example in "Pattern Matching" section in the 1st edition of Programming F# book by Chris Smith. So something might be changed in the later version of F#?
I think the answer to the previous question (and the comments -- "In general, it is an anti-pattern to have a when guard in the last pattern" -- by kimsk) explain the situation.
However, I would not say that having a guard in the last pattern is an anti-pattern - it is the easiest workaround, but I find this somewhat unfortunate, because the when pattern gives you useful information about the values you can expect - and that makes understanding the program easier. Last time I had this problem, I left it there, at least as a comment:
let compareNum x =
let y = 10
match x with
| _ when x = y -> 0
| _ when x > y -> 1
| _ (*when x < y*) -> -1
I'm trying to learn F# by going through some of the Euler problems and I found an issue I haven't been able to figure out. This is my naive solution.
let compute =
let mutable f = false
let mutable nr = 0
while f = false do
nr <- nr + 20
f = checkMod nr
nr
When i do this I get the error message warning FS0020: This expression should have type 'unit', but has type 'bool' on the expression "nr <- nr +20". I've tried rewriting and moving the expressions around and I always get that error on the line below the while statement.
I'm writing this using VS2010 Beta.
Since I can imagine this weg page becoming the 'canonical' place to look up information about warning FS0020, here's my quick summary of the three commonest cases in which you get the warning, and how to fix them.
Intentionally discarding the result of a function that is called only for its side-effects:
// you are calling a function for its side-effects, intend to ignore result
let Example1Orig() =
let sb = new System.Text.StringBuilder()
sb.Append("hi") // warning FS0020
sb.Append(" there") // warning FS0020
sb.ToString()
let Example1Fixed() =
let sb = new System.Text.StringBuilder()
sb.Append("hi") |> ignore
sb.Append(" there") |> ignore
sb.ToString()
Warning is useful, pointing out an error (function has no effects):
// the warning is telling you useful info
// (e.g. function does not have an effect, rather returns a value)
let Example2Orig() =
let l = [1;2;3]
List.map (fun x -> x * 2) l // warning FS0020
printfn "doubled list is %A" l
let Example2Fixed() =
let l = [1;2;3]
let result = List.map (fun x -> x * 2) l
printfn "doubled list is %A" result
Confusing assignment operator and equality comparison operator:
// '=' versus '<-'
let Example3Orig() =
let mutable x = 3
x = x + 1 // warning FS0020
printfn "%d" x
let Example3Fixed() =
let mutable x = 3
x <- x + 1
printfn "%d" x
The following line:
f = checkMod nr
is an equality check, not an assignment as I believe you are intending. Change it to:
f <- checkMod nr
and all should work fine. I'm not sure why you've used the correct syntax on the previous line and not that line...
Also, the line while f = false do should really be simplified to while not f do; equality checks on booleans are rather convoluted.
As I side note, I feel a need to point out that you are effectively trying to use F# as an imperative language. Use of mutable variables and while loops are strongly discouraged in functional languages (including F#), especially when a purely functional (and simpler) solution exists, as in this situation. I recommend you read up a bit on programming in the functional style. Of course, just getting to grips with the syntax is a useful thing in itself.
If you're trying to adopt the functional style, try to avoid mutable values.
For example like this:
let nr =
let rec compute nr =
if checkMod nr then nr else compute (nr + 20)
compute 0
while expressions in F# take a little getting used to if you're coming from an imperative language. Each line in a while expression must evaluate to unit (think void from C++/C#). The overall expression then also evaluates to unit.
In the example:
nr <- nr + 20
evaluates to unit whereas
f = checkMod nr
evaluates to a bool as Noldorin noted. This results in a warning message being reported. You can actually turn the warning off if you so desire. Just put the following at the top of your file:
#nowarn "0020"
I've been programming in an imperative style for a long time, so getting used to the functional programming mindset took a while.
In your example, you're trying to find the first multiple of 20 that passes your checkMod test. That's the what part. For the functional how part, I recommend browsing through the methods available to sequences. What you need is the first element of a sequence (multiples of 20) passing your test, like this:
let multi20 = Seq.initInfinite (fun i -> i*20)
let compute = multi20 |> Seq.find checkMod
The first let generates an infinite list of twentyples (I made that one up). The second let finds the first number in said list that passes your test. Your task is to make sure that there actually is a number that will pass the test, but that's of course also true for the imperative code.
If you want to condense the two above lines into one, you can also write
let computeCryptic = Seq.initInfinite ((*) 20) |> Seq.find checkMod
but I find that pulling stunts like that in code can lead to headaches when trying to read it a few weeks later.
In the same spirit as Brian's post, here is another way to get warning FS0020: In a nutshell, I accidentally tupled the function arguments.
Being an F# newbie, I had a difficult time debugging the code below, which for the second line (let gdp...) gave the warning FS0020: This expression should have type 'unit', but has type '(string -> ^a -> unit) * string * float'. It turns out that line was not the problem at all; instead, it was the printfn line that was messed up. Removing the comma separators from the argument list fixed it.
for country in wb.Regions.``Arab World``.Countries do
let gdp = country.Indicators.``GDP per capita (current US$)``.[2010]
let gdpThous = gdp / 1.0e3
printfn "%s, %s (%.2f)" country.Name, country.CapitalCity, gdpThous