2

How can I import a function from another file in F#? Like you do import in Python. I tried open, #using, nothing works. I looked on the official docs and I still can't figure out how to use it.

Basically, I want something like this:

// Log.fs

module Log = 
    let log = 
        printfn "Hello, World"
// Program.fs
open Log

module main = 
    [<EntryPoint>]
    let main argv =
        log // Not working
        0
stfn
  • 23
  • 4
  • [Import](https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/import-declarations-the-open-keyword) and [module](https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/modules) docs – Jack Hughes Jun 03 '20 at 11:09
  • @JackHughes I looked over that, and I can't get it working. Maybe I'm reading it wrong. Can you please provide an example? Thank you – stfn Jun 03 '20 at 11:16
  • There are examples in the docs I provided. Perhaps it would be more productive for you to give the code you are working on in your question, then we can figure out how to do what you want to do? – Jack Hughes Jun 03 '20 at 11:20
  • Use `open` with the full name of the namespace or module, no `;` at the end, like `open System.Collections`. The statement comes after the namespace declaration, but before anything else. If used inside a module (after `module =... `), it must be indented like anything else. If that doesn't work, please show the non-working code. – Abel Jun 03 '20 at 11:20
  • I provided the code in the question – stfn Jun 03 '20 at 11:27
  • If you use the `open` inside the main module, as the first indednted line, does that work better ? – Pac0 Jun 03 '20 at 11:32
  • Nope, I get the same results – stfn Jun 03 '20 at 11:35
  • Please open .fsproj file, and make sure the `Log.fs` file comes before `Programs.fs`. – Pac0 Jun 03 '20 at 11:39
  • It does, it's in the tag ItemGroup – stfn Jun 03 '20 at 11:41
  • When you say "not working", do you have a compiler error, or is it just that nothing is printed? – Pac0 Jun 03 '20 at 11:46
  • 1
    It's a compiler error. Precisely, **The namespace or module Log is not defined** – stfn Jun 03 '20 at 11:47
  • Oh, I've been messing around with it and I found something else: https://pastebin.com/X3DxUbUR on this code, the compiler says that the function labeled with entryPointAttribute must be the last declaration in the last file in the compilation sequence. What does this mean? – stfn Jun 03 '20 at 12:06
  • That means that your `Program.fs` is not the last. You can see the order in Visual Studio. You probably added `Log.fs` later and didn't adjust the location. F# is sensitive to order of compilation. – Abel Jun 03 '20 at 13:55

2 Answers2

1

The equivalent to import is open.

If I take your pastebin code, it has a bunch of errors indeed, as shown on SharpLab. There are a few things to note here:

  1. F# likes its code ordered. Each file is considered a separate compilation unit and anything that you need from it can only be referenced in a following file, not in a previous one.
  2. Inside a single file, you can create circular references with and, but otherwise, the same applies: whatever type, value, module you want to use, it must already exist and be in scope.
  3. You created a log-value, not a log-function.
  4. You forgot the = sign after the module definitions.

Your original code is this:

// Program.fs
module main
open Log

[<EntryPoint>]
let main argv =
    printfn "Hello"
    log
    0 // return an integer exit code


// Log.fs
module Log

let log =
    printfn "Hello"

This gives the following errors:

error FS0039: The namespace or module 'Log' is not defined.

You get this one because you have a open Log, but the module Log doesn't exist yet.

error FS0010: Unexpected start of structured construct in definition. Expected '=' or other token.

This is about the last let, it must be indented.

error FS0010: Incomplete structured construct at or before this point in implementation file

Same thing, caused by the previous error.

After I change the order of your code, indent it appropriately, change let log to let log(), and add the necessary = signs, it just works, try it out:

// Log.fs
module Log =
    let log() =
        printfn "Hello"

// Program.fs
module main = 
    open Log

    [<EntryPoint>]
    let main argv =
        printfn "Hello"
        log()
        0 // return an integer exit code

Please note that inside a module you can remove the first level of indentation and the =-sign, but only if it is the only module in that file and it is the last file in your project (so generally I would advise against that, to keep it simple, just always indent and always have the =-sign there).

But just to show you an alternative that also works:

// Log.fs
module Log =
    let log() =
        printfn "Hello"

open Log

[<EntryPoint>]
let main argv =         // it is the last in the file or prj, this is allowed
    printfn "Hello"
    log()
    0 // return an integer exit code

Note also that if you place the code in different files, that you must add a namespace declaration at the very top of the file. Typically this will be the default namespace of your whole project.

Abel
  • 56,041
  • 24
  • 146
  • 247
0

This works.I get an error (in VS 2017) when using your syntax Files in libraries or multiple-file applications must begin with a namespace or module declaration. When using a module declaration at the start of a file the '=' sign is not allowed. If this is a top-level module, consider removing the = to resolve this error.

// Log.fs

module Log

let log = 
    printfn "Hello, World"
Jack Hughes
  • 5,514
  • 4
  • 27
  • 32
  • Umm...For me it doesn't. I checked so many times, it still doesn't work. Here's my code: https://pastebin.com/3TwPSBvL . Btw I'm using Monodevelop if it matters – stfn Jun 03 '20 at 12:19
  • I wonder if it is some kind of weird build order problem? Not familiar with Monodevelop so I can't help with that I'm afraid. I've compiled the code on VS 2017 and there is nothing wrong with it, so it must be some weirdness from your tools. – Jack Hughes Jun 03 '20 at 12:35
  • 1
    @stfn, in your pastebin, the `main` function is not at the bottom, and your `Log` module is after the main one. F# requires proper order, what you use must be defined before you use it. Just place the `Log` on top, rest to the bottom, you'll be fine. – Abel Jun 03 '20 at 13:58
  • Here's a good resource: https://fsharpforfunandprofit.com/posts/recipe-part3/ – Abel Jun 03 '20 at 13:59