Для контекста, я играю с шаблоном внедрения частичной зависимости, описанным в https://fsharpforfunandprofit.com/posts/dependency-injection-1/.
Если я хочу передать функцию другой функции (скажем, в корне композиции для 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
=
...
потому что в противном случае моя IDE очень мало помогает при написании _emailUserId.
Вопрос
(добавлено явно, потому что скрывать его в блоке кода немного вводило в заблуждение).
Позволяет ли система типов F # каким-либо образом ссылаться на существующие логические типы или основываться на них?
Например type t = typeof<some inferred function without a manually written type signature>
И может ли система типов F # позволить мне выразить частично примененную функцию, не записывая вручную ее типы аргументов?
E..g 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, где такого рода вещи довольно легко сделать во многих случаях с помощью встроенного синтаксиса.