Reputation: 33
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
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
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
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