F# interactive, API restriction on dll referencing - f#

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.

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.

Use environment variables in F# directives

In FSI, is it possible to run something like
#I #"%APPDATA%/npm/node_modules/blabla/bin/"
instead of
#I #"C:/Users/username/AppData/Roaming/npm/node_modules/blabla/bin/"
Any other options to make it not sensitive to username?
Not likely you can use environment variables in #I FSI directives.
However you may make your package installation agnostic of user name by using the trick with __SOURCE_DIRECTORY__ built-in identifier similar to one I've described in this SO answer:
create a file anchorfsi.fsx with the single line of code
#I __SOURCE_DIRECTORY__
and put it into the directory %APPDATA% points to
add to the command line starting your FSI the term
--load:%APPDATA%\anchorfsi.fsx
Now you can use relative paths in your #r directives.
Just for illustration I put into directory associated with my user profile a folder testlib containing FSharp.Data.dll. The snip below shows how it gets referenced from FSI using the outlined above technique:

(F#, mono for OS X) Errors is happened in visual studio code but send file to fsi successfully (fsi:send file)

I have got errors with the following codes in visual studio code. However, I am able to send the file with command (fsi:send file) and it is executed successfully. It seems I didn't setup the VSC with Ionide properly.
Please feel free to comment.
#load "packages/MathNet.Numerics.FSharp.3.14.0-beta01/MathNet.Numerics.fsx"
open MathNet.Numerics
SpecialFunctions.Gamma(0.5) // Unexpected identifier in implementation file
open MathNet.Numerics.LinearAlgebra
let m : Matrix<float> = DenseMatrix.randomStandard 50 50
(m * m.Transpose()).Determinant()
Syntax check for mistakes and errors in vscode, but the code can be executed in fsi
This directive may only be used in F# script files (extensions .fsx or .fsscript). Either remove the directive, move this code to a script file or delimit the directive with '#if INTERACTIVE'/'#endif'
The namespace or module 'MathNet' is not defined.
Unexpected identifier in implementation file
The first error, "This directive may only be used in F# script files (extensions .fsx or .fsscript)", is telling you how to solve it. You haven't told us the filename of your F# file that you're getting errors in, but I bet it ends with .fs, right? The .fs extension is intended for files that are part of a larger project. A good rule of thumb is that if you have any .fs files, you need a project file (currently that's going to be in .fsproj format, which is an ugly XML file, but VS Code can help you create it).
If you want to use the #load directive, it must be in an F# script file, which means a file with an .fsx extension. (The .fsscript extension is also allowed, but I never see anyone using it in practice. The .fsx extension is the de facto standard).
Simply rename your .fs file to .fsx and that should solve error #1. Then errors #2 and #3 should go away on their own -- they are happening because the F# compiler isn't loading the MathNet namespace, which is because it's ignoring the #load directive in a .fs file. Once the #load directive is processed, then the MathNet.Numerics.fsx file should be loaded, and that file in turn loads all the namespaces needed.
So this was simply because you saved the file as a .fs file when you needed .fsx.

How to set load path in F#?

In F#, I have all the packages in the folder C:\Users\Nick\Documents\Visual Studio 2013\packages, and when I want to load a package file, I have to do:
#load "C:\Users\Nick\Documents\Visual Studio 2013\packages\FSharp.Charting.0.90.9\FSharp.Charting.fsx"
Is it possible to set the load path, and then I could load this file with:
#load "packages\FSharp.Charting.0.90.9\FSharp.Charting.fsx"
or even just
#load "FSharp.Charting.fsx"
By the way, what's the difference with #load and #r?
#load compiles and executes a source file; #r loads an existing assembly.
#I can be used to specify the search path for #r, but I don't think there's an equivalent for #load.
This is all readily available in the documentation.

Cannot open namespace in Fsharp script file

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.

Resources