3

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!

Richard Griffiths
  • 758
  • 1
  • 11
  • 23
  • Well, I'm not very proficient in F#, so I cannot tell you what is wrong, however, this type of combining of functional and declarational way of writing code is not very good idea. :-) – nothrow Nov 30 '12 at 09:07
  • @Yossarian - This is actually a very common pattern in F# – John Palmer Nov 30 '12 at 09:47
  • @JohnPalmer, Really? I'm glad that I didn't seen that, I'm kind of purist. :-) – nothrow Nov 30 '12 at 09:57
  • @Yossarian, I'm deliberately learning F# because I can mix OOP and other non functional styles with functional code. As this is ultimately for work related problems, I'm interested in what can be done well with each language. For purity, I'd have chosen Haskell I think :). I don't believe for general programming its bad, I think it will help me build better code as I can eliminate verbosity in many places. – Richard Griffiths Nov 30 '12 at 21:25
  • Now you've mastered that, you might like [this](http://stackoverflow.com/a/851449/11410) :) – Benjol Dec 03 '12 at 06:41
  • Thank you Benjol! Evernoted :P – Richard Griffiths Dec 03 '12 at 09:18

2 Answers2

5

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)

John Palmer
  • 25,356
  • 3
  • 48
  • 67
  • Your correction Sir is spot on, thank you very much. I started F# on Monday morning this week, after reading online a bit that it was good for various tasks. I wanted a break from VB and the Type provider thing is fascinating. Anyway, I appreciate you and eirik's timely help and explanation. – Richard Griffiths Nov 30 '12 at 21:16
  • A tip for any novices, like myself, wanting to run this in interactive, modify the Dictionary line: let m = System.Collections.Generic.Dictionary() as you'll need the fully qualified name within the interactive session. – Richard Griffiths Nov 30 '12 at 21:18
  • @Richard - you can also do `open System.Collections.Generic` to achieve the same effect. Also - if this is the correct answer hit the green tick to mark to accept it so that anyone in the future can see that it is right. – John Palmer Nov 30 '12 at 21:35
  • The open statement I have at the head of my file, it works when I hit run. It was when I highlight and run in Interactive I found I required the full name, though I guess I could have highlighted the open statement as well. – Richard Griffiths Nov 30 '12 at 22:10
3

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:

  1. The nested if expression has branches that produce values of different types (namely int and unit) and
  2. The outer if expression expects the inner one to have type unit.

Hope this helps :)

eirik
  • 608
  • 3
  • 11