AFAIK, there's not an easy way in Haskell to inspect at the type level what type a field has in a record.
What I mean is that that there doesn't seem to be a type family like
type FieldType :: Type -> Symbol -> Type
that we could invoke in ghci like
:kind! FieldType Person "age"
Why would I want this? For libraries like servant and rel8 that use parameterized records where the types of the fields vary heavily with the type parameter.
@clementd I should try, but HasField uses functional dependencies and I don't know if they're enough to build the FieldType type family on top of them. IIRC, functional dependencies carry less type-level "evidence" than type families, or something like that?
As an alternative to ReaderT and/or polymorphism over the effect monad, I could try to implement some form of "thread-local" storage. 🤔 Some kind of map indexed by ThreadId which would be injected only into those components (like the repository) that require the request-scoped info.
Entries would be allocated / deallocated in the "hoistServer" callback, much like with the ReaderT solution.
Intermediate components could use IO for effects and remain blissfully innocent of the shenanigans.
You might say "Well, that's not a problem, just make those intermediate components that don't care about the connection polymorphic over MonadUnliftIO! Later, when composing the application, they will be injected a repository that does know about the ReaderT and the connection. Problem solved."
That's true, but what if I wanted those intermediate components to be as dumb as possible? Just plain records of functions in IO, no monad transformers, and no polymorphism over the monad, either?
The problem of course is that this solution would be less type-safe. If the repository expects an entry for the current ThreadId to exist in the map, and we forgot to set it earlier in the "hoistServer" callback, that would be a runtime error.
In Servant, the ServerError type has an Exception instance https://hackage.haskell.org/package/servant-server-0.20/docs/Servant-Server.html#t:ServerError
You might speculate that when throwing a ServerError using liftIO . throwIO in a Handler, the ServerError is automatically caught and served as a response, but it ain't so: it's treated as just another exception, and the response code is 500.
btw, why am I throwing a ServerError with HTTP code 200?
I think ServerError is somewhat misnamed: in reality, it can represent any type of response, not only errors.
It's a kind of escape hatch from the typing strictures of Servant: it lets you return any status code and respose body for a request, not just the ones specified in the type-level API.
"registry"-like approaches do seem to make it easier to reuse previously assembled application contexts because the wiring is done through a dictionary-like data structure. You can easily overwrite any key with a different implementation, or with a mock.
Relatedly, it would be a nice feature for Haddock if the instances local to a module could be sorted and grouped for the purposes of documentation and telling a story.
Like "These are the instances for tuples of various sizes" or "this is the base case and these are some instances that recurse".
I vaguely feel that the AGI singularity cult comes from a mode of thinking that's implicitly aligned with Catholic Neo-Platonism. Like, if everything in the universe is either sentient or it isn't and there's no grey area between then you end up in an absolutist position on abortion. So every AI is either AGI or it isn't, and every AGI is God-like.
It's kind of the exact opposite of your basic starting point of queer theory, that binaries don't exist in nature.
I hate package-by-layer so fucking much. "Hey, see this cohesive set of files that together implement a feature? Let's spread them over the four corners of the codebase and send you in fun little Easter egg hunts every two minutes".
In-depth exegesis of the meaning of single letters in my #Git aliases. I'm being so productive you wouldn't believe. Productivity is off the charts right now.
"A relative reference that begins with a single slash character is termed an absolute-path reference. A relative reference that does not begin with a slash character is termed a relative-path reference."
Also, "dani-servant-lucid2" has a public sublibrary with extra definitions, but it seems as if Hackage doesn't display info for public sublibraries yet.