Cannot open namespace in Fsharp script file - f#

When in a separate Fsharp project in a SomeLib.fs file the following code is compiled:
namespace SomeNameSpace
type SomeType =
member this.SomeMember = "Some member"
and you want to reference and use this type in a script file like:
#I #"c:/pathToDll/"
#r "SomeLib.dll"
This is not possible, although the path to the dll is correct and I checked everything. Also when the SomeLib.fs file is in the same project and referenced by #load, you still cannot open the namespace.
I know you can put the type in a module, but I cannot do this as the type has te be used as a Wcf service type.

After a lot of experimental work and surprisingly little info on the internet or in F# books I found out the following:
// Cannot use a relative path
//#I #"bin\Debug"
// Have to use a absolute path
#I #"C:\Development\FSharpNameSpaceTest\SomeCSharpLib\bin\Debug"
// But I can reference a Csharp dll lib
#r "SomeCSharpLib.dll"
// I cannot add a reference to an external F# library dll
// #I #"C:\Development\FSharpNameSpaceTest\NameSpace\bin\Debug"
// #r "NameSpace.dll"
// If I directly load the external fs file, it works"
#load #"C:\Development\FSharpNameSpaceTest\NameSpace\SomeNameSpace.fs"
#load "Library1.fs"
// Namespaces in both the local and the external fs files can only be openend if every single file is loaded instead of referencing the dll.
// Referencing a C# dll is no problem
open FSharpNameSpaceTest
open SomeCSharpLib
open NameSpace
I do not know if this is the most optimal approach but it works. What I will do is, I will create a fsx file for every project that loads the individual fs files in that project and then I will load that fsx file in the fsx file that references the project.
I still find this all very confusing and counterintuitive. But that might be my limited knowledge of the innerworks of F#
Edit: And the right and complete answer is, I didn't implement a default constructor. Still, if you do not wan't to do this, the above approach is an alternative. Thanks to Marc Sigrit.

If on Windows, the slashes in the import directive should be replaced by backslashes.

Related

Cannot Load Deedle in FSharp

I have the most basic of question that should be easy but proving to be a pain. I have a f# FSX file and would like to include Deedle.
I ran the install package and it put it in C:\Users\myName.nuget\packages
Under this directory, the deedle.fsx is in deedle\2.0.4
Now, some of the documentation I have read instructs to do this at the top of the FSX file:
"#I "../../packages/Deedle"
"#load "Deedle.fsx"
Issue#1. That relative path for #I does not work, so I use an explicit path. That resolves that issue.
Issue#2. I cannot get the load statement to find the deedle.fsx file. It appends a bin/net45 to the path.
Therefore, the question is is there a trick I am missing in using this library and how I am referencing it for use?
Thx,
Marc.
try this in your fsx file
#r #"C:\Users\myName\.nuget\packages\deedle\2.0.4\lib\net45\deedle.dll"
change myName to your username.

F#: Why does script file not recognize module?

I create a new F# console application project in Visual Studio 2015
I create a simple new module file called Calc.fs like so:
module Calc
let add a b = a + b
I add an F# script file to the project like so:
open Calc
let c = add 1 2
I get the following compiler errors in the script file:
The namespace or module 'Calc' is not defined
and
The value or constructor 'add' is not defined
Why is my module not recognized by my script file? How can I fix this?
Please note that my script file appears after the module in the order of files in the project:
.fsx files are not compiled together with the rest of the project; they don't "know" about any other code unless you explicitly make it known to them. This is true for any external DLLs (and in fact even many in the .NET Framework) as well as other F# code.
You need to add
#load "Calc.fs"
at the top of the script file to tell the compiler to load that code before evaluating the rest of the script.

how to get f# scripts to call module func?

Just trying to structure an F# library. So far it "appears" that:
I can only reference the C# library from a .fs source file,
and .fs source files are not available to .fsx script files.
Are any of these statements are correct? The examples I read say just use an open, but that only works from a .fs file.
Is there a version of
#r "System.Drawing.dll"
for script files used via f# interactive (fsi) in the same project?
Also, I find the syntax difference between top level modules and lower modules a little strange. Top me it's weird that the top level doesn't have an equals.
module Utilities
module et =
Why not be consistent and have "module moduleName = " for everything?
It is important to note that "References" in Visual Studio in F# only apply to the current project. If you're working in a script file, it does not see the libraries referenced by the project.
To reference a library in a script file (e.g. Script.fsx), you can write (you can use both absolute paths and relative paths):
#r #"C:\<path_to_library>\library.dll"
If you want to load a file that is not a script (e.g. Library.fs) from a script file you can use:
#load "Library.fs"
The fs file itself cannot contain directives like #r, so if the file is using some library that needs to be referenced, you need to have an #r directive in the main script file (to reference the library before loading the source file).
As for the module inconsistency, the main reason is that when you use module Foo or namespace Foo at the top-level, you do not need to indent the rest of the file:
module Foo
let bar = 10
module Sub =
let bar = 12

conditional include in FSharp

I would like to convert a bunch of fs files to fsx files.
Each of those fs file reference class defined in, say, base.fs
So instead of being compiled in the project and relying on the compiler resolution, all would be file based.
That means if I have all those file to include base.fsx, and that one file references another, base.fsx would be included twice.
Does anyone know how to make a conditional include with fsx files ?
The preprocessor documentation states
There is no #define preprocessor directive in F#. You must use the
compiler option or project settings to define the symbols used by the
#if directive.
If you're loading all the files from a single fsx script, then you can load the individual files from the project in the right order and the individual library files do not need to load base.fs directly - the code will be defined, because it has been loaded before.
For example, if you have base.fs:
module Base
let test() = 10
and you have more.fs which does not load base.fs but uses the functions defined there:
module More
let more () =
Base.test() + 1
then you can load all files in F# interactive (in, say, script.fsx) and it will work fine:
#load "base.fs"
#load "more.fs"
More.more()
The only disadvantage is that you won't get IntelliSense when editting more.fs (because the editor does not know about base.fs). To workaround that, it is probably a good idea to keep the files in a project in Visual Studio. But you can still load them in F# interactive for experimentation & testing.

F# interactive, API restriction on dll referencing

How do you solve the error message that looks like this?
`Binding session to 'C:\Program Files (x86)\NLog\.NET Framework 4.0\NLog.dll'...
error FS0193: API restriction: The assembly
'file:///C:\Program Files (x86)\NLog\.NET Framework 4.0\NLog.dll' has
already loaded from a different location. It cannot be loaded from a
new location within the same appdomain.
Code that triggers it, might look like this:
#r #"..\packages\NLog.2.0.0.2000\lib\net20\NLog.dll"
NLog.Config.SimpleConfigurator.ConfigureForConsoleLogging()
It seems that FSI won't load from the given DLL other than by name, so this would sort the problem out:
#I #"..\packages\NLog.2.0.0.2000\lib\net20"
#r #"NLog.dll"
NLog.Config.SimpleConfigurator.ConfigureForConsoleLogging()
#I means to add that folder to the load-path
#r means to reference by dll-path; focusing on name. This means that FSI will use the file name first, looking in the system-wide search path and only then try to use the string after #r as a directory-relative hint.
So by doing it this way, you make the NLog load from your specified directory rather than a system-wide one.

Resources