2009-04-27 12 views
20

¿Es posible dividir un módulo F # entre los archivos?Dividir módulos F # en varios archivos

De acuerdo con el libro que tengo es, pero el libro es probablemente obsoletos (Fundamentos de F #)

+1

Esta pregunta es engañosa, poco claro y un DUP de http://stackoverflow.com/questions/172888/f-definir-y-usar-un-tipo-módulo-en-otro-archivo-en-el-mismo-proyecto que tiene mejores respuestas. OMI que es ... –

Respuesta

11
Al parecer no

:

C:\temp\Tim>type 1.fs 2.fs 

1.fs 


#light 
module Module 

let sayHello1 = printfn "Hello, " 

2.fs 


#light 
module Module 

let sayHello2 = printfn "world!" 

C:\temp\Tim>fsc 1.fs 2.fs 
Microsoft F# Compiler, (c) Microsoft Corporation, All Rights Reserved 
F# Version 1.9.6.2, compiling for .NET Framework Version v2.0.50727 

2.fs(2,1): error FS0191: An implementation of the file or module Module has already been given. 

Actualización: el error ha cambiado en C# 4.0, es ahora:

FS0248 error: dos módulos llamados 'módulo' se presentan en dos partes de este conjunto

donde Module es el nombre completo de su ensamblado, incluida la parte del espacio de nombres.

+2

Eso está mal, porque estoy haciendo un análisis de datos y hay muchas estructuras de datos diferentes, así que estoy generando un archivo F # muy largo ... – TimothyP

+0

Es hora de descomponerlo en .NET regular clases en lugar de módulos? ¿O más de un módulo F #? –

+3

Desafortunadamente, F # no es compatible con clases parciales, por lo que ni siquiera puede dividir una clase regular .NET en varios archivos fuente. –

3

veces me dividir un tipo largo de varios lugares, como este:

module Foo 

type Partial = Bar | BarInt of int 

module Bar 

type Foo.Partial with 
    member x.Extend = 5 


let b = Foo.Bar.Extend 

donde los módulos foo y bar están en diferentes archivos.

4

como Kurt dice, puede agregar métodos de extensión a los tipos, y por lo tanto

// File1.fs 
namespace Foo 

type Mine() = 
    static member f1() =() 

continuación

// File2.fs 
type Foo.Mine with 
    static member f2() =() 

Foo.Mine. // both f1 and f2 here 

Dado que se trata de una clase y no un módulo, se pierde la capacidad de hacer 'abierto Mine '(pero gana la capacidad de sobrecargar); por lo tanto, esta puede o no ser una alternativa aceptable para usted, dependiendo de lo que está haciendo exactamente.

+0

Esto es cierto para Intellisense dentro de File2.fs, pero cuando carga el tipo a través de la reflexión (por ejemplo, typeof (Foo.Mine) .GetMethods(), f2 no ​​se muestra. ¡Gracias por la sugerencia! –

6

Las extensiones de tipo son geniales, y con un poco de suerte permitirán que se muestre el archivo cruzado, mientras sigue siendo intrínseco. Si hace una extensión de tipo en el mismo archivo, se compila en una clase, y la extensión tiene acceso a miembros privados, etc. Si lo haces en otro archivo, es solo una extensión "opcional", como los métodos de extensión estática de C#. (Aunque las especificaciones de F # dicen diferente)

Me sorprendería que esto no se aborde en algún momento, aunque solo sea para el soporte del diseñador. Si las extensiones de tipo intrínseco pudieran estar en cualquier parte del ensamblado, sería bastante ingenioso.

Otra opción, que podría no ser lo que quiere, es la creación de un tipo y un módulo, llamar al módulo del mismo nombre, y luego añadir la bandera ModuleSuffix a ella:

type Foo() = 
    static member Bar = 1 

[<CompilationRepresentationAttribute(CompilationRepresentationFlags.ModuleSuffix)>] 
module Foo = 
    let Baz = 2 

printfn "%d %d" Foo.Bar Foo.Baz 

Esto se utiliza en las bibliotecas F #, para que puedan tener un tipo List o lo que sea, junto con toneladas de elementos auxiliares en un módulo.

+2

Esto está limpio dentro de F #, pero si quiero acceder a estos tipos desde el exterior a través de la reflexión, aparecen como tipos "Foo" y "FooModule". De acuerdo con la respuesta aceptada, no hay forma de que los dos se muestren en el mismo tipo, ¿esta ahí? –

1

En uno de mis proyectos, el objetivo era archivar las operaciones Cp y Rm para separar módulos, pero no es necesario que el usuario abra dos espacios de nombres para ambas tareas.

open Xake.FileTasks 
... 
do! Cp "*/*.exe" "deploy/*.exe" 
do! Rm "*/*.exe" 

Acá mis módulos:

namespace Xake.FileTasks 

[<AutoOpen>] 
module RmImpl = 
    let Rm filemask target = 
... 

y el otro uno:

namespace Xake.FileTasks 

[<AutoOpen>] 
module CpImpl = 
    let Cp filemask target = 
... 
Cuestiones relacionadas