1

我正在尝试使用 F# 签名文件为轻量级数据存储模块创建抽象。这是我的签名文件代码,假设它被称为repository.fsi

namespace DataStorage

/// <summary>Lightweight Repository Abstraction</summary>
module Repository = 
   /// <summary> Insert data into the repository </summary>
   val put: 'a -> unit
   /// <summary> Fetch data from the repository </summary>
   val fetch: 'a -> 'b
   /// <summary> Remove data from the repository </summary>
   val remove: 'a -> unit

这里是对应的实现,我们称之为repository.fs

namespace DataStorage

module Repository = 

    (* Put a document into a database collection *)
    let put entity = ()

    (* Select a document from a database collection *)
    let fetch key = ("key",5)

    (* Remove a document from a database collection *)
    let remove entity = ()

在我的 Visual Studio 项目文件中,我的实现文件 (repository.fs) 上方有签名文件 (repository.fsi)。putremove函数正在被正确解析和验证,没有错误(在实现文件中),但fetch函数在 Visual Studio 中不断给我红色波浪,并显示以下错误消息:

模块“DataStorage.Repository”包含

val fetch: s:string -> string * int

但它的签名指定

val fetch<'a,'b> : 'a -> 'b

各自的类型参数计数不同

有人可以告诉我我做错了什么吗?我的签名文件中的 fetch 函数值是否定义错误?我只是想在我的签名文件中创建一个通用函数('a -> 'b),并让实现将一种类型作为输入并返回另一种类型作为输出。

4

2 回答 2

2

我在 F# 方面还不是很强大,但我认为您在这里以错误的方式使用签名文件。

第一的。以下是修复编译错误的方法:

代替:

let fetch key = ("key",5)

和:

let fetch key = ("key",5) :> obj :?> 'b

你不会得到编译错误。但这个修复在很多情况下实际上没有意义。例如,如果下一个作品:

let a = Repository.fetch(56)

如果您明确指定类型,它将崩溃(在大多数情况下):

let b = Repository.fetch<int, string>(56)

情况是泛型实现应该使用泛型类型进行操作。如果我正确理解了您要做什么,那么当使用签名文件隐藏实现方面时,您应该使用 OOP 和多态性。例如:

namespace DataStorage

[<AbstractClass>]
type Repository<'TKey,'T>() =     
    abstract member put: 'T -> unit
    abstract member fetch: 'TKey -> 'T  
    abstract member remove: 'T -> unit

type IntRepository() =
    inherit Repository<int, int>()
    override self.put item = ()
    override self.fetch index = 5
    override self.remove item = ()

type StringRepository() =
    inherit Repository<int, string>()
    override self.put item = ()
    override self.fetch index = "Hello"
    override self.remove item = ()
于 2013-04-18T09:39:38.443 回答
2

我最近尝试过的一种(一些限制性的)替代方案与泛型相距甚远,但似乎适用于我的场景。基本上 fetch 函数的签名文件现在看起来像这样。

'a -> RepositoryRecord

RepositoryRecord 的实现是代数数据类型。

type RepositoryRecord = | SomeVal1 of int * string | SomeVal2 of string
于 2013-04-18T16:09:46.403 回答