I come from C# background to F#. So far I wrote simple programs and spent a lot of time in F# interactive.
I'm stuck creating a VS F# project with two .fs files.
Sample code:
// part 1: functions
let rec gcd (a : uint64) (b : uint64) =
if b = 0UL then a
else gcd b (a % b)
// part 2: main()
let a, b = (13UL, 15UL)
do printfn "gcd of %d %d = %d" a b (gcd a b)
I'd like to have two .fs files, namely, Alg.fs and Program.fs, so that Program.fs would contain the code I'm working and Alg.fs having algorithms.
Taken steps:
I've created the two files. Compiler gave an 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'
I've inserted module Program and module Alg. The complied program executes only the code from Alg.fs completely ignoring Program.fs...
I'm using F# 2.0 in Visual Studio 2010.
P.S. I've googled and checked some posts, and read documentation on modules and saw relative questions before asking.
Sounds like this is an order-of-files-in-the-project issue. The last file is the entry point ("main method"), sounds like you have Alg.fs last, and you need Program.fs last. You can re-order them via the right-click context menu in VS Solution Explorer.
There are at least three separate things that need to be looked at here:
As mentioned by #Brian, the order of source control files is also the compile order. This matters in F# where type inference is heavily used. Make sure Alg.fs comes before Program.fs in your Visual Studio file list (try this: select Program.fs and hit Alt+Down Arrow until it's at the bottom).
Since Alg.fs and Program.fs are now in modules, you need to actually open the Alg module in Program to get access to its bindings (open Alg), or add the [<AutoOpen>] attribute on Alg.
As #Daniel says, the last problem could be the definition of the entry point to the program. You need either an [<EntryPoint>] attribute on a top level binding that is also the last function in the last file. Alternatively, this defaults to the last binding in the last file anyway, just make sure it has the right signature (see Daniel's link).
Related
After implementing a type checker in Rascal using TypePal, how do I hook it up to the Eclipse IDE? Any resources or repositories to the solution to this problem would be appreciated, Thanks.
in Eclipse search path of the Rascal Navigator view in your project you will find the rascal_eclipse library which contains a good example: demo::lang::Pico::Plugin
in this module you see how to register a language with Eclipse:
registerLanguage("Pico Language", "pico", parsePico); where parsePico is a function reference. Pass your own parameters here. The registerLanguage function comes from util::IDE.
now you can open files with the "IMP editor" in Eclipse and they will use your parser and show syntax highlighting.
next up is registering other effects with the IDE. The library function to call is registerAnnotator. You pass it a function that takes a parse tree for your language and annotates it with error messages:
the messages may be distributed over the tree, using #message or
using a list of #messages at the top of the tree
the error messages will be added as annotations in the editor and registered with the Problem View automatically.
So you have to wire the output of TypePal into the annotator function yourself. Which should be a one-liner.
Alternatively, running type-checks can also be useful after a "save" action. In this case you can register another type of contribition (also in the Pico demo), called builder: builder(set[Message] ((&T<:Tree) tree) messages), and register that with the registerContributions function.
The Message ADT is the same for the annotator and the builder. Both have the effect of adding editor annotations and problems in the view.
Here is some example code taken from an older open-source DSL project called "Bird", https://github.com/SWAT-engineering/bird:
Tree checkBird(Tree input){
model = birdTModelFromTree(input, pathConf = config(input#\loc)); // your function that collects & solves
types = getFacts(model);
return input[#messages={*getMessages(model)}]
[#hyperlinks=getUseDef(model)]
[#docs=(l:"<prettyPrintAType(types[l])>" | l <- types)]
;
}
birdTModelFromTree calls collectAndSolve from TypePal and returns the TModel
getMessage comes from TypePal's Utilities and extracts a list[Message] from the TModel that can be directly communicated to Eclipse via the #messages annotation.
The entire checkBird function is registered as an annotator using the util::IDE function registerAnnotator.
This code hasn't been used for a while, so if you run into trouble, please contact again?
I want to write a quantum program in F# but I don't know how to call Q# operations from F#. How exactly would I do this?
I've tried reading the C# version first but it doesn't seem to translate well to F#.
TL;DR: You have to create a Q# library project (which will yield a .csproj project with only Q# files in it) and to reference it from a purely F# application.
You can not mix F# and Q# in the same project, because it won't compile: Q# compiles to C# for local simulation, and you can't have C# and F# in the same projects. However, you can have two separate projects in different languages which both compile to MSIL and can reference each other.
The steps are:
Create Q# library QuantumCode and write your code in it.
Let's say your code has an entry point with the signature operation RunAlgorithm (bits : Int[]) : Int[] (i.e., it takes an array of integers as a parameter and returns another array of integers).
Create an F# application (for simplicity let's make it a console app targeting .NET Core) FsharpDriver.
Add a reference to the Q# library to the F# application.
Install the NuGet package Microsoft.Quantum.Development.Kit which adds Q# support to the F# application.
You will not be writing any Q# code in FsharpDriver, but you will need to use functionality provided by the QDK to create a quantum simulator to run your quantum code on, and to define data types used to pass the parameters to your quantum program.
Write the driver in F#.
// Namespace in which quantum simulator resides
open Microsoft.Quantum.Simulation.Simulators
// Namespace in which QArray resides
open Microsoft.Quantum.Simulation.Core
[<EntryPoint>]
let main argv =
printfn "Hello Classical World!"
// Create a full-state simulator
use simulator = new QuantumSimulator()
// Construct the parameter
// QArray is a data type for fixed-length arrays
let bits = new QArray<int64>([| 0L; 1L; 1L |])
// Run the quantum algorithm
let ret = QuantumCode.RunAlgorithm.Run(simulator, bits).Result
// Process the results
printfn "%A" ret
0 // return an integer exit code
I posted a full example of the project code here (originally that project dealt with using Q# from VB.NET, but for F# all the steps are the same).
I have a situation where in a Fake script I am trying to grab all the unit test dll's from a path using the Glob (!!) operator.
The issue is that on my machine the glob expansion doesn't work, on other similar Windows 10 machines at work, its fine and finds the dlls.
Below is an example:
let path = [function to generate path]
trace path [would look something like "c:\git\project\src\**\*UnitTest*"]
!! path.ToLower()
|> Seq.iter (fun file -> trace file ) [this would not output anything]
I've tried numerous things:
uninstalling older versions of F#
reinstalling the lastest version
ensuring F# is in my Path
The versions of software I am using are:
Fake v4.63.2
Windows 10
F#4.1
No errors or exceptions are thrown.
Whats the best way to trouble shoot if its an F# or a Fake issue?
How could I work out what version of F# Fake is using?
Update
I've reinstalled F# 4.1 and performed a test using fsi.exe with the following command:
Microsoft (R) F# Interactive version 4.1
<snip>
#r #"packages/FAKE/tools/FakeLib.dll";;
open Fake;;
!! "**\*UnitTests.dll" |> Seq.iter (fun x -> trace x);;
C:\git\project1\bin\Debug\project1.UnitTests.dll
C:\git\project2\bin\Debug\project2.UnitTests.dll
!! "**\*UnitTests.dll".ToLower() |> Seq.iter (fun x -> trace x);;
C:\git\project1\bin\Debug\project1.UnitTests.dll
C:\git\project2\bin\Debug\project2.UnitTests.dll
All the test dlls were found, both with and without the call to ToLower().
When I remove the ToLower() from the script, it now works on my machine.
However, on other peoples machines removing ToLower() on the path causes them not to find any files.
So, is Fake using a different version of the fsi.exe?
I've opened a github issue to see if that sheds any light on it: https://github.com/fsharp/FAKE/issues/1772
In F# as in all .NET languages, the backslash is used for escape sequences in strings.
You need to escape the backslash or use a verbatim string, eg :
let path = "c:\\git\\project\\src\\**\\*UnitTest*"
or
let path = #"c:\git\project\src\**\*UnitTest*"
Fake can work with forward slashes as well :
let path = "c:/git/project/src/**/*UnitTest*"
You'll have to use forward slashes anyway if you want your build script to run on Linux.
An even better option is to use relative paths. Your build script most likely is stored in your project folder. You can write
let path = "src/**/*UnitTest*"
Using the following script, I was able to reproduce the issue and work out that the issue was due to how Windows 10 handles the original casing of the company name, in the path.
I confirmed this by changing company name to ** in the file path expression, the operator worked and found all the dlls.
I remember changing the capitalisation of the company name, from all caps to lower case. If I remove the ToLower() on the path, then the script works fine and finds all the dlls.
This hidden issue, combined with how FAKE does a case sensitive search, doesn't help either.
Powershell
packages\FAKE\tools\FAKE.exe glob.test.fsx
glob.test.fsx
#r #"packages/FAKE/tools/FakeLib.dll"
open Fake
let thePath = """C:\git\company/projectname/**/bin/Debug/*UnitTests.dll"""
sprintf "the path is %s" thePath |> trace
!! thePath.ToLower() |> Seq.iter (fun f -> trace f)
I had a look at the process executing in ProcMon and did not see the original casing of the directory. The NTFS file system is still see this directory as its original casing (see comments below).
I re-image my machine every few months, so this will disappear soon but it was good to understand what was going on.
Thanks to all those that helped narrow the issue down.
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.
I have been trying to use fsunit to test a project. If I limit myself to [<TestMethod>] methods they all show up in the TestExplorer. However, if I try to use [<TestCase(...)>] nothing shows up and no tests get executed.
I expect I have something wrong in my setup but I have no clue as to what it could be. I have NUnit.Framework as well as FsUnit referenced in my code.
This is using Visual Studio 2013, BTW.
An example of what I am trying to do (with a toy Factorial function):
open NUnit.Framework
open FsUnit
[<TestFixture>]
type ``Given the Fact function``()=
[<TestCase(1,1)>]
[<TestCase(2,2)>]
[<TestCase(3,6)>]
...
member t.``the result is calculated correctly``(n, expected) =
let actual = Fact n
actual |> should equal expected
I have tried replacing TestFixture with TestClass but this doesn't seem to do any good, either.
Mark
I got the question answered by Tomas Petricek in an email exchange. It turns out that I had to do more than download the NUnit and FsUnit frameworks to make this work. I also had to download and install the NUnit VsTestAdapter to make it work with the MS testing framework.
This information was actually on the NUnit web site but I just didn't know where to look to find it.
Thanks, Tomas.