F#签名文件和相应实现文件中的通用函数定义
我试图使用F#签名文件为轻量级数据存储模块创建一个抽象。这是我的签名文件代码,假设它叫做repository.fsiF#签名文件和相应实现文件中的通用函数定义,f#,signature-files,F#,Signature Files,我试图使用F#签名文件为轻量级数据存储模块创建一个抽象。这是我的签名文件代码,假设它叫做repository.fsi namespace DataStorage /// <summary>Lightweight Repository Abstraction</summary> module Repository = /// <summary> Insert data into the repository </summary> va
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
在我的VisualStudio项目文件中,我有上面的签名文件(repository.fsi)
我的实现文件(repository.fs)。正在正确分析和验证put和remove函数,没有任何错误(在实现文件中),但fetch函数在visual studio中不断显示红色波形,并显示以下错误消息:
模块“DataStorage.Repository”包含
val fetch: s:string -> string * int
但它的签名表明
val fetch<'a,'b> : 'a -> 'b
val fetch:'a->'b
各类型参数计数不同
有人能告诉我我做错了什么吗?我的fetch函数值在中的定义是否错误
我的签名文件?我只是想在签名文件中创建一个泛型函数('a->'b),让实现将一种类型作为输入,并返回另一种类型作为输出 我在F#方面还不是很强,但我认为您在这里使用签名文件的方式是错误的
首先。以下是修复编译错误的方法:
替换:
let fetch key = ("key",5)
与:
而且不会出现编译错误。
但在许多情况下,这种修复实际上没有意义。例如,如果“下一步”有效:
let a = Repository.fetch(56)
如果明确指定类型,它将崩溃(在大多数情况下):
let b=Repository.fetch(56)
在这种情况下,泛型实现应该使用泛型类型进行操作。如果我正确理解了您试图做的事情,那么在使用签名文件隐藏实现方面时,您应该使用OOP和polymophism。例如:
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 = ()
命名空间数据存储
[]
类型存储库()=
抽象成员put:'T->unit
抽象成员获取:“TKey->”T
抽象成员删除:'T->unit
输入IntRepository()=
继承存储库()
重写self.put项=()
重写self.fetch索引=5
重写self.remove项=()
类型StringRepository()=
继承存储库()
重写self.put项=()
覆盖self.fetch index=“Hello”
重写self.remove项=()
我在F#方面还不是很强,但我认为您在这里以错误的方式使用了签名文件
首先。以下是修复编译错误的方法:
替换:
let fetch key = ("key",5)
与:
而且不会出现编译错误。
但在许多情况下,这种修复实际上没有意义。例如,如果“下一步”有效:
let a = Repository.fetch(56)
如果明确指定类型,它将崩溃(在大多数情况下):
let b=Repository.fetch(56)
在这种情况下,泛型实现应该使用泛型类型进行操作。如果我正确理解了您试图做的事情,那么在使用签名文件隐藏实现方面时,您应该使用OOP和polymophism。例如:
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 = ()
命名空间数据存储
[]
类型存储库()=
抽象成员put:'T->unit
抽象成员获取:“TKey->”T
抽象成员删除:'T->unit
输入IntRepository()=
继承存储库()
重写self.put项=()
重写self.fetch索引=5
重写self.remove项=()
类型StringRepository()=
继承存储库()
重写self.put项=()
覆盖self.fetch index=“Hello”
重写self.remove项=()
我最近尝试过的一种(限制性的)替代方法与泛型有一步之遥,但似乎适用于我的场景。基本上,fetch函数的签名文件如下所示
'a -> RepositoryRecord
RepositoryRecord的实现是一种代数数据类型
type RepositoryRecord = | SomeVal1 of int * string | SomeVal2 of string
我最近尝试过的一个(一些限制性的)替代方案与泛型有一步之遥,但似乎适用于我的场景。基本上,fetch函数的签名文件如下所示
'a -> RepositoryRecord
RepositoryRecord的实现是一种代数数据类型
type RepositoryRecord = | SomeVal1 of int * string | SomeVal2 of string
fetch
的签名是通用的,但实现不是。如果实现只是一个存根,请尝试将其替换为let fetch key=Unchecked.defaultof
以允许其编译。感谢@Daniel的回答,我将尝试一下。fetch
的签名是通用的,但实现不是。如果实现只是一个存根,请尝试将其替换为let fetch key=Unchecked.defaultof
,以允许其编译。感谢@Daniel的回答,我将尝试一下。这很有意义。我正试图以与OCaml中相同的方式使用签名文件。我想这是在.NET世界里做事情的标准方式。感谢@petro.silovsky的时间、想法和解释。这很有意义。我正试图以与OCaml中相同的方式使用签名文件。我想这是在.NET世界里做事情的标准方式。谢谢@petro.silovsky给我的时间、想法和解释。我认为这一点也没有限制。我一直用这种方法。事实上,我甚至可以说这是一个习惯用语。谢谢你的评论。很高兴知道我的想法并非完全错误当然可以也许有人更了解你,但关于你的评论,…离泛型只有一步之遥
,我只想说,我不相信你最初的方法涉及到泛型
。毕竟,泛型
和铸造
之间有区别,我相信在某个时候你最终会这么做。我不认为这是一个限制。我一直用这种方法。事实上,我甚至可以说这是一个习惯用语。谢谢你的评论。很高兴知道我的想法并非完全错误当然可以也许有更博学的人会发表意见,但关于你的评论,…离泛型还有一步之遥,我只想说我不相信它