F# scripting: Add new directory via #I - f#

How could I make this work?
#I (__SOURCE_DIRECTORY__ + #"\bin\Release")
And second questions. Is it possible to do something like:
let path = __SOURCE_DIRECTORY__ + #"\bin\Release"
#I path
?

You can't. The #I and #r commands are really pre-processor instructions that are executed before the code is dynamically compiled by fsi, so they only support string literals. This is logical if you think about it, as the referenced assemblies maybe need to compile the code.
However, the #r and #I command always take relative paths as being from the scripts location, so this
#I #".\bin\Release"
should work just fine (note the dot to ensure it’s a relative not an absolute path).
Note that runtimes relative paths are from the fsi working directory (normally the temp directory) so you do need to use __SOURCE_DIRECTORY__ when loading files from you’re scripts.

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:

Require dll using string path in F#

Is there a way to do this in F#:
let fakeToolsPath = "D:\tools\FAKE\tools\FakeLib.dll"
#r fakeToolsPath
the fake tools are on a different path depending on the build agent that builds the code, so I need to be able to set it dynamically, from an environment variable or some config file.
Three ideas, in order of increasing hackiness - you'll be the judge which one makes most sense in your scenario:
In .fsx script, you can use __SOURCE_DIRECTORY__ to get the directory where the script is located. If your dll is always located in the same directory relative to the script, you can use that as a "hook" to get to it.
There's a command-line --reference argument to fsi.exe that should do what you want. If you're using fake.exe instead, you can use --fsiargs to pass it in (take a look at the link for details).
If everything else fails, create a symlink as a separate build step in your CI job configuration and just hardcode the path in 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

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