F# Interactive, NuGet, and External libraries
Asked Answered
B

1

3

I'm trying to run the demo code for suave (a webserver) in Xamarin Studio 5.9.8 on OS X El Capitan.

module ServerTest =
    open Suave                 // always open suave
    open Suave.Http.Successful // for OK-result
    open Suave.Web             // for config

    startWebServer defaultConfig (OK "Hello World!")

It works as expected when I actually build the code. But when I try running it interactively, with ctrl + return, I get the error The namespace or module 'Suave' is not defined. I've looked around, and it looks like it's possible to use libraries interactively with Visual Studio. Is there a way to get this to work on OS X?

Barbarbarbara answered 7/11, 2015 at 1:40 Comment(5)
Have you tried using the same #r directive?Athanasian
I have not. Do directives only work in *.fsx files? Xamarin won't even let me type #r inside a module.Barbarbarbara
These directives work either in *.fsx files or in FSI (whichever way you interact with it), which is the thing that executes *.fsx files, so that should make sense. The page to which you linked applies to *.fsx and FSI, and not to Visual Studio. It just happens to use VS as demonstration vehicle.Athanasian
I'm trying to do this within an *.fs file. Should I just use a *.fsx file by default?Barbarbarbara
I added #if INTERACTIVE #r "Suave" #endif in the *.fs file but now I'm getting ` Unable to find the file 'Suave' in any of /Library/Frameworks/Mono.framework/Versions/4.0.5/lib/mono/4.5`Barbarbarbara
A
5

When you build your code, the information about referenced DLLs is contained not in the code itself, but elsewhere (the project file). But when you execute the code in FSI, all FSI sees is the code. It doesn't have a project file from which to get references.

But since FSI still needs to load referenced DLLs occasionally (otherwise, it wouldn't be very useful), it offers a way to encode them in the code. This way is described in the page you linked - specifically, the #r directive.

Unfortunately, these directives are not supported when you build the code with the compiler. The compiler will generate an error when it sees them.

So it would seem that you have a choice: either execute the code with FSI or build it with compiler. Can't use the same code for both.

Fortunately, there are a couple of tricks to work around this.

First, you could leverage a special conditional compilation variable called INTERACTIVE and put the #r directive inside an #if such that only FSI will see it, but compiler won't:

#if INTERACTIVE
   #r "./path/to/my.dll"
#endif

Second, you could create a separate script file that will load references and then load your actual code file:

#r "./path/to/my.dll"
#load "./my_code.fs"

And then execute this script file with FSI.

In both these cases, the paths are relative to the script file.
This means that the "not found" error you're getting is probably due to incorrect path to the Suave DLL. I seriously doubt that the DLL is located in the same directory with the code file. And also that it has no extension.

Athanasian answered 7/11, 2015 at 3:15 Comment(4)
My path was #r ./../packages/Suave.0.32.1/lib/net40/Suave.dll which seems like it would be really brittle in practice, depending on how often the library in question is being updated.Barbarbarbara
That's why you shouldn't do anything very complicated in scripts. For complicated stuff, build the code and run the executable. Scripts are best reserved for experiments or lightweight tasks that change often, so it's relatively expensive to rebuild on every change.Athanasian
Also, if you insist on running it as a script, you probably shouldn't use the directory structure that is aimed at building. All this hassle with putting packages in special places, tagged with version and framework, - that's all to facilitate the build. If your solution is script-based, you're better off keeping your references right next to the script. After all, that how an *.exe file would work anyway.Athanasian
Where should I add the #if statement? If I add it in my .fsx file I get error FS0010: Unexpected keyword 'open' in interaction. Expected incomplete structured construct at or before this point, ';', ';;' or other token. Adding just #r [path-to-dll] in .fsx works though..Braiding

© 2022 - 2024 — McMap. All rights reserved.