对于上下文,我正在使用 https://fsharpforfunandprofit.com/posts/dependency-injection-1/ 中概述的部分依赖注入(inject)模式.
如果我想将一个函数传递给另一个函数(比如在 DI 的组合根中),能够为 FSharp 类型引擎提供一些关于我正在尝试做什么的提示会很有用,否则它有点爆炸成无用的困惑,直到一切正常。 为此,我想引用“现有功能的部分应用版本的类型”
例如,假设我有设置
let _getUser logger db userId =
logger.log("getting user")
User.fromDB (db.get userId)
let _emailUserId sendEmail getUser emailContents userId =
let user = getUser userId
do sendEmail emailContents user.email
// composition root
let emailUserId =
let db = Db()
let logger = Logger()
let sendEmail = EmailService.sendEmail
let getUser = _getUser logger db
_emailUserId sendEmail getUser
我想像 _emailUserId 一样提供类型提示
let _emailUserId
// fake syntax. is this possible?
(sendEmail: typeof<EmailService.sendEmail>)
// obviously fake syntax, but do I have any way of defining
// `type partially_applied = ???` ?
(getUser: partially_applied<2, typeof<_getUser>>)
emailContents userId
=
...
否则在编写 _emailUserId 时我的 IDE 几乎得不到帮助。
问题
(明确添加是因为将其隐藏在代码块中有点误导)。
F# 的类型系统是否允许以任何方式引用或构建现有的推断类型?
如type t = typeof<some inferred function without a manually written type signature>
F# 的类型系统是否可以让我表达部分应用的函数而无需手动编写其参数类型?
例如 type partial1<'a when 'a is 'x -> 'y -> 'z> = 'y -> 'z>
, 可能像 partial1<typeof<some ineferred function without a manually written signature>
一样使用?
虽然我仍然感谢对我正在使用的模式的反馈,但这不是核心问题,只是上下文。在我看来,这个问题普遍适用于 F# 开发。
我发现获得我想要的东西的唯一方法是硬编码完整的函数类型:
let _emailUserId
(sendEmail: string -> string -> Result)
(getUser: string -> User)
emailContents userId
=
...
这会导致签名重复,在很大程度上抵消了 F# 强大的推理系统的优势,并且在将此模式扩展到玩具 StackOverflow 示例之外时很难维护。
令我惊讶的是,这不是显而易见的或不受支持的——我使用丰富类型系统的另一个经验是 Typescript,在许多情况下,使用内置语法可以很容易地完成这类事情。
最佳答案
您可以定义类型别名,这基本上是现有类型的新名称:
type SendMail = string -> string -> Result
type GetUser = string -> User
您可以在任何您想要/需要向编译器提供类型提示的地方使用它们,但它们不是新类型或子类型,并且编译器本身仍会推断原始类型。您可以为任何类型定义它们;上面的是函数签名,因为那是你的例子,但它们也可以用于记录类型或 .NET 类。
对于函数参数,您可以像这样使用它们:
let _emailUserId (sendMail : SendMail) (getUser : GetUser) emailContents userId =
/* .... */
关于types - 是否可以在 F# 中引用推断类型或提取函数参数类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54317527/