John-Michael Martello
John-Michael Martello

Reputation: 33

Why is F# inferring my function implements IComparable?

I'm a hobbyist programmer (cook by trade) that's currently trying to teach myself F# and functional programming in general.

Anyway, I was fooling around with DeflateStream and wrote the following two functions:

let Compress compressMe =
    let ds = new DeflateStream(File.Create("compressed.txt"), CompressionMode.Compress)
    File.OpenRead(compressMe).CopyTo(ds)
    ds.Close()

let Decompress =
    let ds = new DeflateStream(File.OpenRead("compressed.txt"), CompressionMode.Decompress)
    ds.CopyTo(File.Create("decompressed.txt"))
    ds.Close()

In the body of the main function they are called one right after the other like this:

Compress args.[0]
Decompress

However, if compressed.txt doesn't exist when the program is run Decompress throws a FileNotFoundException which is surprising because the only thing that could throw this is the call to File.OpenRead("compress.txt"). After about an hour I figured out that Decompress was implementing IComparable and was being executed before the call to it in the main function. I found that by changing its definition to let Decompress () = [...] it no longer implemented IComparable and my code executed as it was intended to. Can anyone tell me why F# was infering IComparable and why such and inference would cause the function to execute before the main function marked with [<EntryPoint>]? Also, please forgive the imperitive style of my code, I'm incredibly new at this.

Thanks in adavance.

Upvotes: 3

Views: 188

Answers (3)

Joh
Joh

Reputation: 2380

As others have pointed out, the absence of parentheses in the declaration is significant.

let Decompres = ...

declares a variable of type unit. This type is used to represent "data" (even if this data doesn't encode much information), and it implements IComparable like any other data-oriented type.

let Decompress() = ...

declares a function, and functions in F# are not comparable, probably because there is no universally accepted notion of equality on functions.

I can't see that the "IComparable-ness" of Decompress had anything to do with the exception you got.

Upvotes: 0

John Palmer
John Palmer

Reputation: 25516

When you write something like

let value = 
    //some long calculation
[<Entrypoint>]
let main args = ...

The compiler executes the long calculation before main. This is because you probably use the value later in your code. To suppress this, as you found, you need to use let value() = ....

I am not sure where Icomparable is coming from, but this is the key to what is happening.

Note, if you write

let a = ...
let b = ...

The compiler will gurantee a is calculated before b executes.

Upvotes: 4

Gideon Engelberth
Gideon Engelberth

Reputation: 6155

I'm not entirely sure about the IComparable bit, but the issue you have is that without the parentheses, the compiler is treating Decompress as a value not a function. This would be similar to if you had written.

let compressedName = "compressed.txt"

in that case, compressedName is now a value. Adding the parentheses tells the compiler that this is a function whose code must be called each time the function is rather than a value initialized once (before the entry point) by the code you wrote.

Upvotes: 4

Related Questions