如何在单声道 (OS X) 中加载 .fsx 文件,并使用内部 types\functions?

How to load a .fsx file in mono (OS X), and use the internal types\functions?

我通过 brew install mono 在 OS X 上安装了单声道,当我在终端中 运行 fsharpi 时加载了 F# v.4.01。

我有一个 .fsx 文件,其中定义了一些类型和函数。我希望在 fsifsharpi 的别名)中交互使用它们。为此,我启动了 fsi 和 运行 #load "pc.fsx;;" - 文件被加载和编译,我看到了通用命名空间下的所有类型定义和函数类型。出于某种原因,REPL 无法识别自定义类型(因此我无法使用类型构造函数)和函数,因此我收到错误 FS0039:The value or constructor '<insert type or function name>' is not defined。我该如何克服这个问题?

编辑: 该文件名为 Temp.fsx,内容包含在名为 Temp.

的模块中

文件内容:

module Temp =

  open System

  /// Type that represents Success/Failure in parsing
  type Result<'a> =
      | Success of 'a
      | Failure of string

  /// Type that wraps a parsing function
  type Parser<'T> = Parser of (string -> Result<'T * string>)

  /// Parse a single character
  let pchar charToMatch =
      // define a nested inner function
      let innerFn str =
          if String.IsNullOrEmpty(str) then
              Failure "No more input"
          else
              let first = str.[0]
          if first = charToMatch then
                  let remaining = str.[1..]
              Success (charToMatch,remaining)
          else
              let msg = sprintf "Expecting '%c'. Got '%c'" charToMatch first
              Failure msg
  // return the "wrapped" inner function
      Parser innerFn

  /// Run a parser with some input
  let run parser input =
      // unwrap parser to get inner function
      let (Parser innerFn) = parser
      // call inner function with input
      innerFn input

fsi 的编译输出:

$ fsi

F# Interactive for F# 4.1
Freely distributed under the Apache 2.0 Open Source License

For help type #help;;

> #load "Temp.fsx";;
[Loading /Users/asaf/programming/PCfs/Temp.fsx]

namespace FSI_0002
  module Temp = begin
    type Result<'a> =
      | Success of 'a
      | Failure of string
    type Parser<'T> = | Parser of (string -> Result<'T * string>)
    val pchar : charToMatch:char -> Parser<char>
    val run : parser:Parser<'a> -> input:string -> Result<'a * string>
  end

我还没有在 .fsx 文件中测试它本身,但我认为它应该可以工作。您可以将其放入 .fs 文件中,比方说 File1.fs 并在顶部放置一个模块声明,然后执行 #load "File1.fs"

然后在 FSI 中你可以将 xxy 引用为 File1.xxy;;,你可以将其创建为 File1.B "jds";;.

module File1

type A =
    | B of string
    | C of int

let xxy = B "sds"

通常你只需将代码从编辑器直接发送到 FSI 并在编辑器中工作,这样你就不会遇到这个问题...

例如

根据你的类型我得到:

File1.Failure "blah";;
val it : File1.Result<'a> = Failure "blah"

编辑 fsx 文件示例:

以下是我的评论中提到的一些变体。文件名为 Script11.fsx,模块名称为 Temp(指定时)。它刚刚加载到 PowerShell 中的 fsi 会话 运行:#load @"Script11.fsx";;

1) 没有模块名称声明。带有文件名的前缀。

open System
type A =
    | B of string
    | C of int

let xxy = B "sds"

//> Script11.xxy;;
//val it : Script11.A = B "sds"
//>

2) 模块名称声明。没有缩进。带有模块名称的前缀。

module Temp
open System

type A =
    | B of string
    | C of int

let xxy = B "sds"

//> Temp.xxy;;
//val it : Temp.A = B "sds"
//>

3) 缩进的模块名称(您的版本),带有 等号,这会将模块放在文件名 space 中。您可以看到它以 module Temp = begin 开头。带有文件名和模块名的前缀。

module Temp =
    open System

    type A =
        | B of string
        | C of int

    let xxy = B "sds"

//> Script11.Temp.xxy;;
//val it : Script11.Temp.A = B "sds"
//>

4) Autoopen与否的区别:

//[<AutoOpen>]
module Temp =
    open System

    type A =
        | B of string
        | C of int

    let xxy = B "sds"

如果您注释掉 Autoopen,您将需要通过在模块名称前加上前缀来引用模块的内容。

open Script11;;
Temp.xxy;;
//val it : Temp.A = B "sds"

如果你使用Autopen那么你仍然需要打开文件名但是你可以直接访问你模块里面的东西。

> open Script11;;
> xxy;;
//val it : A = B "sds"

长话短说,如果你有顶级声明,通常你不需要Autoopen,如果你不缩进和创建额外的名字space你可以直接访问内容.否则你正在创建一个本地模块,显然你必须使用路径。参见 Modules

当您在 F# 交互中 #load 一个 .fsx 文件时,该文件中的所有定义最终都在以该文件命名的模块中,大写。因此,例如,如果您 #load "pc.fsx",那么您所有的定义都将在名为 Pc.

的模块中结束
#load "pc.fsx"

let r = Pc.Success "value"

只需在 fsx 的顶部声明一个具有相同名称的 AutoOpen 模块,就可以了:

[<AutoOpen>]
module Temp

open System

/// Type that represents Success/Failure in parsing
type Result<'a> =
    | Success of 'a
    | Failure of string

/// Type that wraps a parsing function
type Parser<'T> = Parser of (string -> Result<'T * string>)

/// Parse a single character
let pchar charToMatch =
    // define a nested inner function
    let innerFn str =
        if String.IsNullOrEmpty(str) then
            Failure "No more input"
        else
            let first = str.[0]
            if first = charToMatch then
                let remaining = str.[1..]
                Success (charToMatch,remaining)
            else
                let msg = sprintf "Expecting '%c'. Got '%c'" charToMatch first
                Failure msg
    // return the "wrapped" inner function
    Parser innerFn

/// Run a parser with some input
let run parser input =
    // unwrap parser to get inner function
    let (Parser innerFn) = parser
    // call inner function with input
    innerFn input

在 fsi 中加载:

» fsharpi

F# Interactive for F# 4.1
Freely distributed under the Apache 2.0 Open Source License

For help type #help;;

> #load "Temp.fsx";;
[Loading /Users/kostas/workspace/fsharp/Temp.fsx]

namespace FSI_0002
type Result<'a> =
    | Success of 'a
    | Failure of string
type Parser<'T> = | Parser of (string -> Result<'T * string>)
val pchar : charToMatch:char -> Parser<char>
val run : parser:Parser<'a> -> input:string -> Result<'a * string>

> run (pchar 'f') "foo";;
val it : Result<char * string> = Success ('f', "oo")
> Failure "42";;
val it : Result<'a> = Failure "42"
>