F#签名文件中的通用函数定义和相应的实现文件

时间:2013-04-18 05:22:26

标签: f# signature-files

我正在尝试使用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.fsi) 我的实现文件(repository.fs)。 put 删除函数正在被正确解析和验证,没有错误(在实现文件中),但 fetch 函数一直给我红色视觉工作室中的波浪形,并出现以下错误消息:

模块'DataStorage.Repository'包含

val fetch: s:string -> string * int

但其签名指定

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

各自的类型参数计数不同

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

2 个答案:

答案 0 :(得分:2)

我最近尝试的一种(一些限制性的)替代方案与仿制药相比有一步之遥,但似乎适用于我的方案。基本上,fetch函数的签名文件现在看起来像这样。

'a -> RepositoryRecord

并且RepositoryRecord的实现是一种代数数据类型。

type RepositoryRecord = | SomeVal1 of int * string | SomeVal2 of string

答案 1 :(得分:1)

我在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 = ()