2016-10-07 3 views
2

Я установил mono на OS X через brew install mono, а F # v. 4.01 загружается, когда я запускаю fsharpi в терминале.Как загрузить файл .fsx в моно (OS X) и использовать внутренние типы функции?

У меня есть файл .fsx, который определяет некоторые типы и функции. Я хочу использовать их в интерактивном режиме в fsi (псевдоним для fsharpi). Для этого я запускаю fsi и запускаю #load "pc.fsx;;" - файл загружается и компилируется, и я вижу все определения типов и типы функций под общим пространством имен. По какой-то причине REPL не распознает настраиваемые типы (поэтому я не могу использовать конструкторы типов) и функции, поэтому я получаю ошибку FS0039: The value or constructor '<insert type or function name>' is not defined. Как я могу это преодолеть?

EDIT: Файл имеет имя 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 
+0

Что вы имеете в виду по пользовательским типам? Можете ли вы показать более конкретный пример того, как типы определены в файле и как они вызывается. FSI помещает типы под настраиваемое пространство имен. Является ли он внутри некоторого модуля/пространства имен? Что делать, если вы #load или #r .fs-файл? – s952163

+1

Тип Результат <'a> = | Успех 'a | Сбой строки Код не находится внутри модуля или пространства имен. – asafc

+0

Поместите в модуль как минимум. Я не проверял другие способы обхода. – s952163

ответ

3

Просто заявить в верхней части 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" 
> 
1

Я не проверял его в .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" 

Edit, например файла FSX:

Вот некоторые из вариантов, упомянутых в моем комментарии. Имя файла - Script11.fsx, имя модуля - Temp (если указано). Он просто загружается в сессию fsi, работающую внутри PowerShell: #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) Объявление в модуле. Не с отступом. Префикс с именем modulename.

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) отступ имя_модуль (ваш вариант), с знаком равенства, который будет поместить модуль внутри пространства имен файлов. Вы можете видеть это, начиная с 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 вам нужно будет обратиться к содержимому вашего модуля предваряя его с MODULENAME.

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

Если вы используете Autopen, то вам все равно нужно открыть файл, но вы можете получить прямой доступ к вещам внутри вашего модуля.

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

Чтобы вырезать длинную историю Короче говоря, как правило, вы не должны нуждаться в AutoOpen, если у вас есть декларация верхнего уровня, и если вы не отступа и создать дополнительное пространство имен можно непосредственно получить доступ к содержимому. В противном случае вы создаете локальный модуль, и, очевидно, вы должны использовать этот путь. См. Modules.

+0

Отправка файла в 'fsi' удобна, когда я пишу файл, чтобы проверить правильность кода, но конечным результатом является внешний пользователь для загрузки'.fsx' в терминале (через 'fsi') и применить одну функцию к некоторому входному файлу для ее обработки. – asafc

+0

@asafc да, конечно, я также использую файлы fsx, они удобны в качестве блокнота, потому что они не скомпилированы fsc. вы можете загрузить файл .fs с объявлением модуля. К сожалению, у меня нет моно, но позже будет протестировать версию fsx. но в основном это загружается в fsi, т.е. я не отправляю его из edito. – s952163

+0

благодарим вас за пересмотренный ответ, он намного яснее и помог мне понять все эти неудобные комбинации, которые я испытал сам, не понимая, что происходит. – asafc

1

Когда вы #load a .fsx файл в F # interactive, все определения в этом файле заканчиваются в модуле, названном после файла, заглавными. Так, например, если вы #load "pc.fsx", то все ваши определения будут в конечном итоге в модуле с именем Pc.

#load "pc.fsx" 

let r = Pc.Success "value" 
+0

Это не работает, как описано. Загрузка файла '.fsx' не приводит к созданию модуля с именем файла с заглавной буквы. Опять же, я использую mono в OS X - может быть, поведение 'fsi' отличается в Windows? – asafc

+0

Я использую это в Mono на Linux, отлично работает. –