Here is some code In F# that I tried following the book Programming F# byChris Smith:
(*
Mega Hello World:
Take two command line parameters and then print
them along with the current time to the console.
*)
open System
[<EntryPoint>]
let main (args : string[]) =
if args.Length <> 2 then
failwith "Error: Expected arguments <greeting> and <thing>"
let greeting, thing = args.[0], args.[1]
let timeOfDay = DateTime.Now.ToString("hh:mm tt")
printfn "%s, %s at %s" greeting thing timeOfDay
// Program exit code
0
main(["asd","fgf"]) |> ignore
There is an error in main that says: This expression was expected to have type 'String[]' but here ahs type "a list'. But string[] is an array of string. SO I don't understand my error.
string[] is indeed an array of strings, but ["asd", "fgf"] is not - it's a list, which is why you get that error.
To create an array instead, use [|"asd"; "fgf"|] (note that, both in lists and arrays, ; is used as a separator - , creates tuples).
In addition, you can't have code after a function marked as EntryPoint. And even if you could, calling that function makes no sense as it will already be called automatically with the command line arguments - that's the point of the EntryPoint attribute.
Related
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.
TL;DR: how to write a function like fprintfn that accesses and closes a file and behaves similar to printf family of functions, but won't throw an ObjectDisposedException on multiple arguments?
As a convenience embedded function, I found myself writing the following code, which worked for a while:
let fprintfn a b =
use handle = File.AppendText("somelogfile.log")
printfn a b |> ignore // write to stdout
fprintfn handle a b // write to logfile
// works
fprintfn "Here we are, %i years of age" 42
// throws ObjectDisposedException
fprintfn "Here we are, %i years of age in $i" 42 DateTime.Now.Year
The error is raised whether I use use or using and as soon as the number of arguments exceeds 2.
After some head-scratching, I concluded that the new fprintfn function above creates a closure as soon as I use it with more than one print format argument. Which seems to make sense to some extend, albeit a bit more hidden then in cases where you return a closure explicitly (i.e. returning an actual fun x -> something which accesses the handle variable).
Now the question is: how can I rewrite the above statement while retaining the convenience of the original fprintfn function use and syntax, without having it throw the ObjectDisposedException?
PS: A preferred way of writing the above function would be to use the following, which allows all fprintfn syntax, but that will throw the same exception already when you use a single print format argument.
let fprintfn a =
use handle = File.AppendText("somelogfile.log")
printfn a |> ignore
fprintfn handle a
fprintf "Test" // works
fprintf "Test: %i" 42 // throws ODE
You are right that fprintf creates a continuation and returns it, so that by the time you call that continuation, the file is already closed.
But you can go one level deeper and use kprintf. It lets you provide a "continuation" - i.e. a function that receives the formatted string and does whatever with it.
let fprintfn a =
let doPrint s =
use handle = File.AppendText("somelogfile.log")
printfn "%s" s
fprintfn handle "%s" s
kprintf doPrint a
And then, of course, you can simplify that a bit by using File.AppendAllText:
let fprintfn a =
let doPrint s =
File.AppendAllText("somelogfile.log", s + "\n")
printfn "%s" s
kprintf doPrint a
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() =
I am playing with the F# Interactive Console and comparing the runtime of some numeric operations. On this code the total runtime seems to double only be repeating the declaration of one variable.
In VS 2010 I do:
open System.Diagnostics
let mutable a=1
Then I select this below and run it with Alt+Enter
let stopWatch = Stopwatch.StartNew()
for i=1 to 200100100 do
a <- a + 1
stopWatch.Stop()
printfn "stopWatch.Elapsed: %f" stopWatch.Elapsed.TotalMilliseconds
it takes more or less: 320 ms
now i select this and hit Alt+Enter:
let mutable a=1
let stopWatch = Stopwatch.StartNew()
for i=1 to 200100100 do
a <- a + 1
stopWatch.Stop()
printfn "stopWatch.Elapsed: %f" stopWatch.Elapsed.TotalMilliseconds
almost double: 620 ms
The same block but including the declaration at the top takes almost double. Shouldn't it be the same since I declare the variable before Stopwatch.StartNew() ? Does this have to do with the interactive console?
I have the same results using the #time directive.
I'm not convinced any of the answers yet are quite right. I think a is represented the same in both cases. And by that I mean an individual type is emitted dynamically wrapping that mutable value (certainly on the heap!). It needs to do this since in both cases, a is a top-level binding that can be accessed by subsequent interactions.
So all that said, my theory is this: in the first case, the dynamic type emitted by FSI is loaded at the end of the interaction, in order to output its default value. In the second case, however, the type wrapping a is not loaded until it is first accessed, in the loop, after the StopWatch was started.
Daniel is right - if you define a variable in a separate FSI interaction, then it is represented differently.
To get a correct comparison, you need to declare the variable as local in both cases. The easiest way to do that is to nest the code under do (which turns everything under do into a local scope) and then evaluate the entire do block at once. See the result of the following two examples:
// A version with variable declaration excluded
do
let mutable a=1
let stopWatch = Stopwatch.StartNew()
for i=1 to 200100100 do
a <- a + 1
stopWatch.Stop()
printfn "stopWatch.Elapsed: %f" stopWatch.Elapsed.TotalMilliseconds
// A version with variable declaration included
do
let stopWatch = Stopwatch.StartNew()
let mutable a=1
for i=1 to 200100100 do
a <- a + 1
stopWatch.Stop()
printfn "stopWatch.Elapsed: %f" stopWatch.Elapsed.TotalMilliseconds
The difference I get when I run them is not measureable.
This code fragment is compiled:
let test =
let x = 1
printfn "%A" x
If the last line is removed, there is the following compilation error:
error FS0588: Block following this 'let' is unfinished. Expect an expression.
What does this message mean? In C#/C++ I would expect the "Unused variable" warning in such situation, but F# gives something different.
In F#, a function has to bind a name to a value.
The printfn statement has a return value, and this is ultimately what gets bound to test.
Without the printfn statement you only have a statement binding the value 1 to x. The compiler will be expecting something to bound to test. Because the test function stops at this point, this is why you are seeing the compiler errror.
If you want your function just to do stuff (possibly with side effects), you should end your function with ()