I send this line to F# interactive console in Visual Studio
assert (2=3)
To my surprise, the console does not report errors, but
val it : unit = ()
Similarly, if I run
printf ("hello!")
assert (2=3)
printf ("hello2")
on an REPL, I got "hellohello2" without any error messages.
How could I make the F# interactive tell me 2=3 is wrong?
Under the cover, the assert keyword translates to a method call to the Debug.Assert method from the .NET library (see the method documentaiton). This has a conditional compilation attribute [Conditional("DEBUG")], meaning that the call is only included if the symbol DEBUG is defined.
By default, this is not the case in F# Interactive. You can do that by adding --define:DEBUG to the command line parameters for fsi.exe. This will be somewhere in the options of your editor, depending on what you are using. For example, in Visual Studio, you need something like this:
EDIT: How to do something like this if you do not want to modify the command line parameters? This really depends on what exactly behaviour you want. The default behaviour of assert is that it shows a message box where you can either terminate the program or ignore the error. You could do that using:
open System.Windows.Forms
let ensure msg b =
let res =
MessageBox.Show("Assertion failed: " + msg +
"\n\nDo you want to terminate the exection? Press 'Yes' " +
"to stop or 'No' to ignore the error.", "Assertion failed",
MessageBoxButtons.YesNo)
if res = DialogResult.Yes then exit 42
ensure "Mathematics is broken" (2=3)
Related
If I have:
import demo::lang::Exp::Concrete::WithLayout::Syntax;
if ((Exp)`<IntegerLiteral e> + <IntegerLiteral e>` := (Exp)`5 + 6`) {
println(e);
}
This prints 6. Is this a possible bug or a design decision, e.g. because of performance considerations? It should of course not print anything, since e cannot be matched to both 5 and 6. This is, however, in contrast to matching with ADTs, where this is caught, i.e.:
data ExpNum = numb(int n) | add(ExpNum e1, ExpNum e2);
if (add(numb(x), numb(x)) := add(numb(5), numb(6))) { println(x); }
Will not print a number, while it does print a number when using numb(5) instead of numb(6).
Ps. I ran the example both from Rascal source using Eclipse Plug-in Development (using a forked version merged with the latest version of Rascal), as well as on two machines using the official Eclipse plugin. The plugin, however, returned the following on both machines:
|stdin:///|(4,46,<1,4>,<1,50>): Java compilation failed due to with classpath [/home/wouter/eclipse//plugins/org.eclipse.equinox.launcher_1.3.100.v20150511-1540.jar]: package org.eclipse.imp.pdb.facts.type does not exist
The reason why I am asking is because, somewhat similarly, ConcreteListVariablePattern automatically throws a RedeclaredVariable-exception without checking if the match result's value is equivalent to the variable in the environment, in contrast to e.g. QualifiedNamePattern which checks if the result is equivalent to the value in the environment in case of a readily declared variable.
Thank you!
This is definitely a bug: the variable e is declared twice (without warning), the match succeeds and the binding to second e is printed.
Expected behavior would be that a RedeclaredVariable exception is thrown.
A work around is as follows:
if ((Exp)`<IntegerLiteral e1> + <IntegerLiteral e2>` := (Exp)`5 + 6` && e1 == e2) {
println(e1);
}
I have 2 files: Asm.fs, AsmTest.fs
Asm.fs
namespace Assembler
[<Measure>] type ln
[<Measure>] type col
[<Measure>] type port
type Addr = int<ln> * int<col> * int<port>
module Asm =
let emptyAddr : Addr = (-1<ln>, -1<col>, -1<port>)
AsmTest.fs
module Assembler.Tests
[<Test>]
let someTest() =
let x = Asm.emptyAddr
When I debug someTest() code, I get that x = null, what am I doing wrong?
P.S. files in the different projects visual studio projects. Asm.fs in the Assembler project and AsmTest.fs in the AssemblerTest project.
I found an interesting behavior. My problem will be resolved, if I add some file (even empty) to the Assembler project. Can anyone explain this behavior?
The debugger sometimes has issues showing the correct values. For me however, having exactly the same Asm.fs and AsmTest.fs like this:
module Assembler.Tests
open NUnit.Framework
[<Test>]
let someTest() =
let x = Asm.emptyAddr
Assert.IsNotNull x
the test passes and if I set a breakpoint at the assertion, x is correctly shown as {(-1, -1, -1)}
As the code that you show does not compile as it is (Block following this let is unfinished. in someTest), could you try my test above and/or show your complete test method?
Using your code I can reproduce the behaviour. If I set my projects to console applications, my test will fail as well. So, it seems that for console projects, not having any other file or an [<EntryPoint>] surprisingly skips the initialization of module values. For me, the compiler at least issues a warning Main module of program is empty where I use x in the test. The solution to the problem is therefore:
make sure you treat warnings as errors
have an [<EntryPoint>] for console applications
use library projects for libraries
UPDATE
The general question is: how to use verbose syntax of F# correctly? Verbose syntax is the syntax which is close to OCaml syntax, i.e. syntax with many commas etc.
OLD TEXT
I want to turn light syntax off in F# to have verbose syntax which is closer to OCaml.
I wrote the following code
#light "off"
let k=3.14;;
and got an error on let:
Unexpected keyword 'let' or 'use' in implementation file
What is correct implementation file structure without light syntax?
The problem is that you have written this inside a .fsi file - which is an FSharp Interface definition file; it has nothing to do with fsi.exe (FSharp Interactive).
The message "Unexpected keyword 'let' or 'use' in implementation file" is a tell - interface definitions were expected. Simply use a .fs extension.
If you want reuse ML code, consider changing the file extension to .ml, and add a #nowarn "62" directive at the beginning to ignore the legacy warning.
#nowarn "62"
#light "off"
let div2 = 2;;
let f x =
let r = x % div2 in
if r = 1 then
begin "Odd" end
else
begin "Even" end
I don't see anything wrong but... why the two ;? Are you compiling it or running in fsi?
I have written this code which compiles and works perfectly in VS.NET 2010
module ConfigHandler
open System
open System.Xml
open System.Configuration
let GetConnectionString (key : string) =
ConfigurationManager.ConnectionStrings.Item(key).ConnectionString
however when I do a control + A and Alt + Enter to send this to FSI I get an error
ConfigHandler.fs(2,1): error FS0010: Unexpected start of structured construct in definition. Expected '=' or other token.
OK.
So I change my code to
module ConfigHandler =
open System
open System.Xml
open System.Configuration
let GetConnectionString (key : string) =
ConfigurationManager.ConnectionStrings.Item(key).ConnectionString
Now Control + A, Alt + Enter is successful and I FSI nicely tells me
module ConfigHandler = begin
val GetConnectionString : string -> string
end
However now If I try to compile my code in VS.NET 2010, I get an error message
Files in libraries or multiple-file applications must begin with a namespace or module declaration, e.g. 'namespace SomeNamespace.SubNamespace' or 'module SomeNamespace.SomeModule'
How can I have both? Ability to compile in VS.NET and the ability to send modules to FSI?
There is a tiny -- but crucial -- difference between your two snippets of code which is to blame here.
F# has two ways to declare a module. The first, a "top-level module", is declared like this:
module MyModule
// ... code goes here
The other way to declare a module is as a "local module", like so:
module MyModule =
// ... code goes here
The main differences between the "top-level" and "local" declarations are that the local declaration is followed by an = sign and the code within a "local" module must be indented.
The reason you get the ConfigHandler.fs(2,1): error FS0010: Unexpected start of structured construct in definition. Expected '=' or other token. message for the first snippet is that you can't declare top-level modules in fsi.
When you added the = sign to your module definition, it changed from a top-level module to a local module. From there, you got the error Files in libraries or multiple-file applications must begin with a namespace or module declaration, e.g. 'namespace SomeNamespace.SubNamespace' or 'module SomeNamespace.SomeModule' because local modules must be nested within a top-level module or a namespace. fsi doesn't allow you to define namespaces (or top-level modules), so if you want to copy-paste the entire file into fsi the only way it'll work is if you use the compilation directives as #pad mentioned. Otherwise, you can simply copy-paste the local module definitions (without the containing namespace) into fsi and they should work as expected.
Reference:
Modules (F#) on MSDN
The common solution is to keep the first example and create a fsx file which references the module:
#load "ConfigHandler.fs"
You have advantage of loading multiple modules and writing plumbing code for experiment.
If you really want to load ConfigHandler.fs directly to F# Interactive, you can use INTERACTIVE symbol and compiler directives:
#if INTERACTIVE
#else
module ConfigHandler
#endif
which works for both fsi and fsc.
If I compile the following module into a dll
namespace MyNs
module SomeModule =
do printfn "module loading"
let x = 23
then reference the dll in FSI and execute the command open MyNs.SomeModule "module loading" does not print immediately. It only prints when I access x which causes all the top level let and do bindings to execute (normal behavior I know in the .NET world). Is there any way, perhaps via an attribute on the module, I can indicate that module should load immediately upon opening in FSI?
Opening a module never does anything at runtime. It just puts all the symbols in the opened namespace in scope for unqualified access below the open statement.
Section 12.5 of the language spec is what you want to read - this details when the static initialization of a module will run.
Given that, the only time when this initialization is run automatically, as far as I know, is for last module in an exe.
I.e. I don't think there is a direct way to accomplish what you want.
If you have reflective access to the module:
ModuleType.TypeInitializer.Invoke(null, null)
will invoke the static initialization.
You can add the AutoOpen attribute to the module
[<AutoOpen>]
module SomeModule =
do printfn "module loading"
let x = 23
However this will only print the module loading message when you reference x.
Not sure if you found the solution to your problem but in my case I wanted to start an agent when my website was starting and it was indeed starting twice like you mentioned.
What I did was set a method let start() = inside the module and invoke the method using a static do xxx.start() from my main Site type.
Found that by reading the language spec Kurt linked.