How do you use Console.Readline in F#? Unlike Console.Writeline, it isn't being honored when I call it.
If you use
let s = Console.ReadLine
you are only building a delegate that points to the ReadLine function. You need to say
let s = Console.ReadLine()
to actually execute the function. This is just like C# syntax, except type inference means you don't get a compiler warning.
What do you mean by "it isn't being honored"? Here's a small console app I've just written in VS2010b1, and it works fine:
open System
let line = Console.ReadLine()
Console.WriteLine("You wrote {0}", line)
// Just to make it pause
let unused = Console.ReadLine()
Are you trying to run the code from F# Interactive within Visual Studio? If so, that may be the issue, as Brian's post explains.
However, I haven't seen the same problem when using F# Interactive from the command line. Here's a complete transcript of a session:
Microsoft F# Interactive, (c) Microsoft Corporation, All Rights Reserved
F# Version 1.9.6.16, compiling for .NET Framework Version v4.0.20506
Please send bug reports to fsbugs#microsoft.com
For help type #help;;
> open System;;
> let line = Console.ReadLine();;
Hello world
val line : string = "Hello world"
Running Brian's looping code from F# Interactive didn't show the same problem.
Bottom line: It seems like this is broken in F# Interactive in Visual Studio, but not when running interactively from the command line or in a full console app.
I don't have a Beta1 box handy, but I know that in the past we've had a bug where ReadLine() would see the background commands that communicate between the interactive UI and the background process that runs your F# code. It may be interesting to investigate what
let Foo max =
let rec Loop i =
if i < max then
let line = System.Console.ReadLine()
printfn "line = %s" line
Loop (i+1)
Loop 1
Foo 12
prints when you highlight it and 'Send to Interactive'. I think possibly you'll see a few unexpected interesting lines, followed by lines you type into the window.
// is the right way if you're not wanting to use a return of anything typed into readline
Console.ReadLine() |> ignore
Related
I have written a F# script in FSI using Ionide in VS Code. It's a great tool, but I am getting a warning from Ionide Lint suggesting a code improvement:
'Lint: Seq.map f (Seq.map g x) might be able to be refactored into Seq.map (g >> f) x.'
I have about 6 Seq.map functions all piped together with |> which I am happy with.
There is also a green wiggly line that is annoying me. I don't agree with the suggestion, and want the wiggly line to go away. How can I tell Ionide to stop making this suggestion?
I have turned off Lint globally in the VS Code settings
"FSharp.linter": false,
I think Ionide uses FsharpLint: http://fsprojects.github.io/FSharpLint/
This supports suppressing of lint messages like this:
[<SuppressMessage("NameConventions", "InterfaceNamesMustBeginWithI")>]
type Printable =
abstract member Print : unit -> unit
Something like that might work for you as well. I just turned it off.
This is the directive to disable this particular message in code:
open System.Diagnostics.CodeAnalysis
[<SuppressMessage("Hints", "") >]
Place above the block that is producing this 'error'.
I try to play with fsharp under Ubuntu (and yes, I slowly figure out that it is more pain than fun), I already installed Mono, VSCode and Ionide extension and I can create and build F# projects. Unfortunately when I run simple F# script via F# Interactive:
printfn "bar"
In terminal window I get:
>
- printfn "bar"
-
- ;;
bar
val it : unit = () F# 4.0 (Open Source Edition)
> ^?^?414;3R^?^?^?^?^?^? the Apache 2.0 Open Source License
The strange sequence ^?^? looks like unrecognized terminal escape codes, but when I use bash from within VSCode there is nothing like this.
What's more the strange sequence reappears after every command executed in FSI:
> let j = 9;;
val j : int = 9
> printfn "foo";;
foo
val it : unit = ()
> ^?^?
Does anyone have the same problem and knows a solution (or maybe just knows a solution)?
EDIT: Problem occurs mostly when I execute commands via Ionide Alt+Enter shortcut
This looks like the https://github.com/Microsoft/vscode/issues/19766 bug. VS Code 1.9 introduced a new setting, terminal.integrated.flowControl, that defaults to true. The ^? characters you're seeing (and any ^S and ^Q characters that might show up) come from this "flow control" feature, which doesn't play well with F# Interactive. Change your VS Code settings to set terminal.integrated.flowControl to false and your problem should go away.
I'm just learning F#, and setting up a FAKE build harness for a hello-world-like application. (Though the phrase "Hell world" does occasionally come to mind... :-) I'm using a Mac and emacs (generally trying to avoid GUI IDEs by preference).
After a bit of fiddling about with documentation, here's how I'm invoking the F# compiler via FAKE:
let buildDir = #"./build-app/" // Where application build products go
Target "CompileApp" (fun _ -> // Compile application source code
!! #"src/app/**/*.fs" // Look for F# source files
|> Seq.toList // Convert FileIncludes to string list
|> Fsc (fun p -> // which is what the Fsc task wants
{p with //
FscTarget = Exe //
Platform = AnyCpu //
Output = (buildDir + "hello-fsharp.exe") }) // *** Writing to . instead of buildDir?
) //
That uses !! to make a FileIncludes of all the sources in the usual way, then uses Seq.toList to change that to a string list of filenames, which is then handed off to the Fsc task. Simple enough, and it even seems to work:
...
Starting Target: CompileApp (==> SetVersions)
FSC with args:[|"-o"; "./build-app/hello-fsharp.exe"; "--target:exe"; "--platform:anycpu";
"/Users/sgr/Documents/laboratory/hello-fsharp/src/app/hello-fsharp.fs"|]
Finished Target: CompileApp
...
However, despite what the console output above says, the actual build products go to the top-level directory, not the build directory. The message above looks like the -o argument is being passed to the compiler with an appropriate filename, but the executable gets put in . instead of ./build-app/.
So, 2 questions:
Is this a reasonable way to be invoking the F# compiler in a FAKE build harness?
What am I misunderstanding that is causing the build products to go to the wrong place?
This, or a very similar problem, was reported in FAKE issue #521 and seems to have been fixed in FAKE pull request #601, which see.
Explanation of the Problem
As is apparently well-known to everyone but me, the F# compiler as implemented in FSharp.Compiler.Service has a practice of skipping its first argument. See FSharp.Compiler.Service/tests/service/FscTests.fs around line 127, where we see the following nicely informative comment:
// fsc parser skips the first argument by default;
// perhaps this shouldn't happen in library code.
Whether it should or should not happen, it's what does happen. Since the -o came first in the arguments generated by FscHelper, it was dutifully ignored (along with its argument, apparently). Thus the assembly went to the default place, not the place specified.
Solutions
The temporary workaround was to specify --out:destinationFile in the OtherParams field of the FscParams setter in addition to the Output field; the latter is the sacrificial lamb to be ignored while the former gets the job done.
The longer term solution is to fix the arguments generated by FscHelper to have an extra throwaway argument at the front; then these 2 problems will annihilate in a puff of greasy black smoke. (It's kind of balletic in its beauty, when you think about it.) This is exactly what was just merged into the master by #forki23:
// Always prepend "fsc.exe" since fsc compiler skips the first argument
let optsArr = Array.append [|"fsc.exe"|] optsArr
So that solution should be in the newest version of FAKE (3.11.0).
The answers to my 2 questions are thus:
Yes, this appears to be a reasonable way to invoke the F# compiler.
I didn't misunderstand anything; it was just a bug and a fix is in the pipeline.
More to the point: the actual misunderstanding was that I should have checked the FAKE issues and pull requests to see if anybody else had reported this sort of thing, and that's what I'll do next time.
In Visual Studio 2010, the following F# sequence works as expected in Release mode (ignores UnauthorizedAccessException), but does not work correctly in Debug mode (breaks on UnauthorizedAccessException, even if I have set "Common Language Runtime Exceptions: Thrown = false, User-Unhandled = true").
open System
open System.IO
module private MyTestModule =
let rec private getAllFiles dir = seq {
if String.IsNullOrWhiteSpace dir |> not then
let getAuthorizedItems getItems dir =
try getItems dir
with :? UnauthorizedAccessException -> [||]
// Debugger stops here on UnauthorizedAccessException, but shouldn't...
yield! getAuthorizedItems Directory.GetFiles dir
for subDir in getAuthorizedItems Directory.GetDirectories dir do
yield! getAllFiles subDir }
// etc.
However, if I do not nest the getAuthorizedItems function inside the sequence, but place it at module level instead, the debugger works correctly.
Note:
I have looked at the generated IL code, and the exception handler is where it should be in both cases (is not modified/optimized in any way);
I know that System.Core must be preloaded in order for sequences to be displayed correctly in the debugger, but that is not related to my issue.
Are there any special rules for handling exceptions in sequences at debug time in F#?
Edit
After my reporting the issue, the F# team very quickly started to track it. It seems to be a minor bug related to the fact that, in Debug mode, some of the generated code is marked as ‘External Code’, even though it is user code. For the time being, one can use the workarounds suggested in pad's answer. Another workaround ist to turn off "Enable Just My Code" in the VS debugging options.
I'm able to reproduce the bug on my machine using F# 2.0/.NET 4.0 without VS2010 SP1 installed. It could be the case that this bug has been fixed in VS2010 SP1 as #svick couldn't reproduce it. It turns out this bug is still present after VS2010 SP1 update.
I think it's a bug of handling exception in nested functions inside sequence expression, changing the nested function to catch any exception doesn't affect the behaviour:
let getAuthorizedItems getItems dir =
try getItems dir
with ex -> [||]
This is a minor bug; you can bypass it in many ways:
It works in Release mode, inside fsi and even runs in Debug mode outside Visual Studio.
Declaring the nested function as inline makes it work in Debug mode.
Turning on Optimize code option makes it work again.
Not using nested functions inside seq also helps.
If it hasn't been fixed, I suggest you file a bug report at fsbugs at microsoft dot com.
Starting here - Embedding F# interactive - I've been trying to embed FSI in my application.
However, I'm getting weird stuff back from StandardOutput.
for example, in standard FSI, if I send this:
let a = 3;;
I get this back:
[empty line here]
val a : int = 3
[empty line here]
> |
(with Pipe representing the input position)
But if I send let a = 3;; to StandardInput, I get this back on StandardOutput:
>
val a : int = 3
|
Has anyone else tried this? Is there something I'm doing wrong, and if not is there any way to work around this? None of the things I've tried so far work, and before I try the 'worse' thing I can think of (set a timer after sending stuff, add the > myself on timeout), I'd like to know if there is a better way!
When embedding F# Interactive, Visual Studio uses the --fsi-server:<some value> parameter.
As far as I know, this does two things:
Changes the way output is printed (instead of printing >, it prints SERVER-PROMPT> on a separate line, so it should be easier to remove it from the output and detect state when input is expected)
It also starts some .NET Remoting channel that you can use to stop execution of commands in F# Interactive (e.g. if it runs into an infinite loop) and it can also provide some completion information.
The F# Interactive pad in MonoDevelop F# plugin uses the flag (see source code on GitHub). I think it works mostly right, but I believe it sometimes prints additional \n in the output.