Problems with F# callstack in Visual Studio - f#

It looks that F# debugger doesn't work properly in VS 2015. Let me illustrate it on simple console program:
let f1 =
printf "hello 1"
printf "hello 2" //1
[<EntryPoint>]
let main argv =
f1 //2
0
I set breakpoints on lines //1 and //2 and start the debugger.
First BP being hit is //1 while it should have been //2. Why is that?
Also at this moment I cannot navigate to the topmost level of the callstack. I.e. when I double click on the callstack entry which should have navigate me to line //2 VS tells me that "Source Not Available". Why is that?
These two problems doesn't stop me from debugging but nevertheless make pretty unhappy.

First BP being hit is //1 while it should have been //2. Why is that?
f1 is not a function, it is a value of type unit. So its value is going to be constructed before main is called. You'll note that if you call f1 multiple times, it only prints once because the value has been initialized. If you change f1 to this:
let f1() = //etc
Then it will behave as you expect.
I suspect your callstack issue is because you are expecting main to be called before f1's initializer, which isn't correct.

Related

Using f# to mimic linux touch command, need help implementing

I am trying to write a f# program which mimics the touch command in linux, it checks a file paths exists if it does time stamp is updated, if it doesnt exist file is created. How do i implement this correctly?
I've tried using .net functions which i think essentially do the functions i need. I am working with file.exists, file.create and file.setlastaccesstime
// Learn more about F# at http://fsharp.org
open System.IO
type Filepath = string
let touch =
let checkExists filePath =
if File.Exists filePath
then Result.Ok (filePath:Filepath)
else Result.Error "File does not exist"
let path = Console.ReadLine()
let update =
path = Console.ReadLine()
if File.Exists(path)
File.Create(path)
else File.SetLastAccessTime(path, DateTime.Now)
[<EntryPoint>]
let main argv =
printfn "Touch command for windows"
-> touch()
-> update()
0 // return an integer exit code```
Your code has several problems. I'll try to go through them one by one.
First, the indentation of the code in your question is totally messed up. If this is a direct copy and paste from your code, the first thing we need to do is fix the indentation: in F#, indentation is significant, and determines code blocks. (If your question's indentation is messed up because you fiddled with the indentation in the Stack Overflow question editor and your actual code indentation is fine, then consider this a refresher on how F# indentation works).
In F#, these two code blocks do something different:
if value = 5 then
printfn "Five"
printfn "Value: %d" value
This will always print "Value: 3" or "Value: 27" or whatever, and will also print the word "Five" if the value is exactly 5. But this next code block does something else:
if value = 5 then
printfn "Five"
printfn "Value: %d" value
This will either print nothing at all, or it will print the word "Five" followed on the next line by "Value: 5". That's because the second printfn function call is indented at the same level as the first one, meaning it's part of the if block.
Also, a let statement needs to be followed either by a value on the same line, or by an indented block:
let value = 5
let otherValue =
if value < 5 then
5
else
3
After this is executed, the value of otherValue will be 3. Also, the code block under let otherValue = will only be executed once. That's because otherValue is not a function, it's a value. If you wanted otherValue to be a function, you would need to give it parameters:
let calculateValue inputValue =
if inputValue < 5 then
5
else
3
And now you can call that function like:
let value = 5
let otherValue = calculateValue value
// Now otherValue is equal to 3
This brings us to the second problem your code has, which is that you clearly intend touch and update to be functions, but you didn't give them parameters. Which means that they're values which are only executed once. You need to turn let touch = into let touch () = to make touch a function instead of a value, and same for update.
Another problem you have is more of a design issue: your update function is doing two things. It's reading a value from the console, and it's taking actions based on that value. It's much better design to have each function do only one thing: let your update function take path as a parameter, and then elsewhere you can have the code that reads path from the console and calls update path. This makes it much easier to write unit tests that test the update function, because instead of having to somehow figure out how to hook up your unit tests to stdin, you can just have your tests call your update function.
Another issue that Guran pointed out in a comment (thanks!) is that your update function has the logic backwards. You wrote "if file exists, create file, else set last access time". It should be the other way around. I missed this in the first version of this answer, so I've updated my fixed code below to correct the order of the if...then...else block in update.
Another issue I see is: what is your touch function (currently it's a value, but you clearly intended it to be a function) supposed to be doing? The only thing inside your let touch = block is other function definitions; the touch code block never actually calls the functions it defines. Which means it's useless: by having those function definitions inside the touch code block, you're hiding them from any code outside the touch code block, yet the touch code block never calls them. Functions defined at the top level of a module are visible to any code that can access the module. Functions (and variables) defined inside a code block are visible only in the scope of that code block. This is useful for encapsulating things that shouldn't be visible to the outside world, e.g. in the following example:
let counter() =
let mutable value = 0
let update() =
value <- value + 1
value
update
Here, the value variable inside counter() is not accessible to the rest of the world. Also, notice how I've written update with no parentheses as the last line of the let counter() = code block: that means that the function named update will be the return value of counter(). In other words, when you call counter(), you get a function that, each time you call it, will return a new value that is the previous value plus 1. But two different counters are separate from each other:
let a = counter()
let b = counter()
let a1 = a()
let b1 = b()
let a2 = a()
let b2 = b()
printfn "A1: %d" a1
printfn "A2: %d" a2
printfn "B1: %d" b1
printfn "B2: %d" b2
This will print "A1: 1", "A2: 2", "B1: 1", and then "B2: 2". Now as an exercise, what would happen if I replaced let counter() = with let counter = in the above code? (I would also have to change let a = counter() to let a = counter, and same for let b = ...). Try to guess what would happen, then try it and see if you were right. (Hint: values, unlike functions, are only executed once).
And one final thing: the arrows in your main function are not correct. That's not what the -> operator is for. If you need to call several functions in a row, just write the function calls one after the other.
Okay, that's as much as I can do right now to help you fix your code's problems. There are more issues (it would be better to get your paths from argv rather than from Console.ReadLine(), for example) but those can wait until you have a bit more F# experience under your belt. Here's your code with just the fixes I've mentioned so far. Oh, and one more fix: I'm deleting the let touch = line since I can't tell what you intended to put in your touch function. So here's your code, somewhat fixed but still in need of more fixes:
open System.IO
type Filepath = string
// NOTE: This function is unused. Why do you have it?
let checkExists filePath =
if File.Exists filePath
then Result.Ok (filePath:Filepath)
else Result.Error "File does not exist"
let update path =
// Note: the "then" and "else" blocks are swapped from your original code
if File.Exists(path)
then File.SetLastAccessTime(path, DateTime.Now)
else File.Create(path)
[<EntryPoint>]
let main argv =
printfn "Touch command for windows"
let path = Console.ReadLine()
update path
0 // return an integer exit code

F# incorrect type and another incorrect type in the function call

Not sure what's off about this code. I want to use this as the main function to print a string or return not enough arguments. What's incorrect about this VS15 isn't very helpful in this instance.
[<EntryPoint>]
let main argv =
if (List.length argv) >= 1 then
printfn "Hello %s" argv.[0]; 0
else
printfn "Not enough arguments"; 1
main ["Test"]
Even though you didn't specify what error you get and where it appears (please always do that when asking questions), I can see what's wrong with your code: you're treating argv as if it was a List, but a .NET program entry point must accept an argument of type Array - specifically, array of strings - string[].
If you switch out List.length for Array.length, the function will compile.
[<EntryPoint>]
let main argv =
if (Array.length argv) >= 1 then
printfn "Hello %s" argv.[0]; 0
else
printfn "Not enough arguments"; 1
Now, if you want to call this function, you would want to supply an argument that is an array, not List. In F#, the brackets are used to denote a list. If you want to denote an array, you need to use bracket-pipes instead:
main [| "Test |]
EDIT in response to comment:
Normally you wouldn't need to "call" the entry point function explicitly. Entry point is the "start" of the program, there are no other functions calling it. This is why the entry point function must be the last function in the last file of the program. If you do place any code after the entry point, the compiler will give you an error.
The way you wrote the call main ["Test"], I assumed you just wanted to execute this call in F# interactive, which is a popular way of verifying your code without building and running it. Once you are ready to compile, you should remove this call.
Finally, I'd like to point out that you're actually accessing the array twice: first to check its length, then to fetch its first item. You can do both in one step using pattern matching:
[<EntryPoint>]
let main argv =
match argv with
| [|name|] -> printfn "Hello %s" name; 0
| _ -> printfn "Not enough or too many arguments"; 1
And look: this way, the program actually became slightly more valid. If you look closer, you'll notice that your original program accepts any number of arguments, but only actually uses the first one. This is a bit "unclean", so to say. The above version using pattern matching does one better: it will take exactly as many arguments as is needed for its function, or print an error message otherwise.

Why don't I see results of printfn called outside the main entrypoint (F#)

I have a F# console application that calls functions in other modules to perform its work from the main function entrypoint. I have a series of printfn in these other functions to provide me with information on the running of the program.
When compiled in DEBUG mode, all the statements print to the console. However, when compiled in RELEASE mode the only statements that print to the console are those that are directly inside the main entrypoint function.
What can I do to print statements for info in these other modules?
A code example is provided below:
Program.fs
[<EntryPoint>]
let main argv =
printfn "%s" "start" // prints in RELEASE and DEBUG mode
File1.Run
printfn "%s" "end" // prints in RELEASE and DEBUG mode
System.Console.ReadLine() |> ignore
0 // return an integer exit code
File1.fs
module File1
let Run =
let x = 1
printfn "%d" x // this won't print in RELEASE mode
yep you are (kindof) right - it will not print as Run is an expression here and it seems the compiler is optimizing it away in release mode.
And why should it not? In a perfect (pure/referential transparent) world you have an expression of type unit that can only have a single value () ... and you don't even use or remember the value!
To be honest I don't know if this is a bug or a feature ;)
anyway this simple trick will help you and indeed you should not use an expression with effects in the way you did:
let Run () =
let x = 1
printfn "%d" x
...
File1.Run ()
see - now it's a function and get's called at the right time and your output is back ;)
btw: if you are interested in this kind of stuff you an either use tools like Reflector (which I do not have at hand at the moment) or just use IL DASM (a tool VS should install anyway) - if you look at the compiled debug/release assemblies you will notice that nowhere something like this:
IL_001f: call class [FSharp.Core]Microsoft.FSharp.Core.Unit File1::get_Run()
can be found in the release version if you use the expression.
I played with it a bit and you have to get creative to make the compiler do this stuff:
For example
let reallyNeed v =
if v = ()
[<EntryPoint>]
let main argv =
printfn "%s" "start" // prints in RELEASE and DEBUG mode
File1.Run |> reallyNeed
printfn "%s" "end" // prints in RELEASE and DEBUG mode
System.Console.ReadLine () |> ignore
0 // return an integer exit code
works (it prints your 1) - while
ignore File1.Run
or
let reallyNeed v = ignore v
don`t ;) - seems like you have to actually use the value somewhere :D

Entry point issue in F#

I have the following program :
let readStoriesInQAForm =
printfn "Inside the let!"
0
[<EntryPoint>]
let main argv =
printfn "Ah! entering point to the main!"
System.Console.ReadKey() |> ignore
0 // return an integer exit code
I was expecting to get the following output (since main is the entry point, and there is no function call):
Ah! entering point to the main!
But I get this, when I compiler and run it in VS 2013:
Inside the let!
Ah! entering point to the main!
What is my mistake?
As John Palmer describes in his answer, F# code is executed from top to bottom. The let keyword binds a value to a name - in this case, the value 0 is bound to the readStoriesInQAForm name.
Apart from primitive values, you can also bind functions to names; F# is a Functional programming language, so functions are values too. If you bind a function to a name, you can execute that function by invoking it.
However, readStoriesInQAForm isn't a function - it's a primitive value (0), and it gets bound before main is called, in order to make that value available for main. In this particular case, the way the let binding is defined, it has a side-effect of printing to Standard Out when the binding occurs. (In general, in Functional Programming, the more you can avoid side-effects, the better.)
If you want to avoid this behaviour, change the let binding from a a primitive value to a function:
let readStoriesInQAForm () =
printfn "Inside the let!"
0
Better yet would be to bind the name to the value without any side-effect:
let readStoriesInQAForm = 0
In a F# program, the code is essentially run from top to bottom, so that any values needed later are available.
For example, if you had written:
[<EntryPoint>]
let main argv =
printfn "Ah! entering point to the main!"
printfn readStoriesInQAForm
System.Console.ReadKey() |> ignore
0 // return an integer exit code
The observed behaviour makes perfect sense as it would be illogical to jump out of main to calculate a constant value.
To avoid this issue, you want to make readStoriesInQAForm a function, like so:
let readStoriesInQAForm() = ...
You're not declaring a function, you're declaring a value. It's missing ():
let readStoriesInQAForm() =

let bindings and constructors in F#

I am defining a stopwatch in F#:
open System.Diagnostics
let UptimeStopwatch = Stopwatch.StartNew()
and I am printing every 3 seconds with
printfn "%A" UptimeStopwatch.Elapsed
and every time i'm getting "00:00:00.0003195" or something similarly small. Is F# calling the constructor every time I reference UptimeStopwatch? If so, how do I get around this ad achieve the desired result? This is a confusing intermingling of functional and imperative programming.
F# seems to interpret statements like
let MyFunction = DoSomething()
and
let MyFunction() = DoSomething()
differently. The first binds the return value of DoSomething() to the variable MyFunction, and the second binds the action DoSomething() to the function MyFunction().
My usage of UptimeStopwatch was correct, and the error was elsewhere in my implementation.
I see you already found a problem elsewhere in your code, but the two lines in your question still take some time to run and, interestingly, you can make the overhead smaller.
When I run the two lines in your sample, it prints a value around 0.0002142. You can make that smaller by storing the elapsed time using let, because there is some overhead associated with constructing a representation of the printf format string (the first argument):
let UptimeStopwatch = Stopwatch.StartNew()
let elapsed = UptimeStopwatch.Elapsed
printfn "%A" elapsed
This prints on average a number around 0.0000878 (two times smaller). If you use Console, the result is similar (because the Elapsed property is obtained before Console is called and nothing else needs to be done in the meantime):
let UptimeStopwatch = Stopwatch.StartNew()
System.Console.WriteLine(UptimeStopwatch.Elapsed)

Resources