Closed tricktron closed 2 years ago
After some more thinking and some discussions I decided to remove the monad transformers again and just passthrough the Global
argument because
the key to performance is elegance, not battalions of special cases. The terrible temptation to tweak should be resisted unless the payoff is really noticeable. -- Jon Bentley and Doug McIlroy.
Let's resist the temptation of monad transformers because the payoff is not worth it.
Fixes #49.
The pure core only reads the
Global
state. As a result, I don't need theState
monad and can replace it with theReader
monad to clearly reflect this requirement in the type system as well.This provides an interesting design space with the following three options:
No Transformers, just Thread/Passthrough the Global argument:
lift
.Global
parameter. This makes not only the high-level functiongetTypeOnHover
more noisy but also all intermediary functions, which do not actually use theGlobal
argument. In addition, nothing prevents the user to modify theGlobal
between function calls (e.g. between thefindToken
and thetokenToQName
step, which violates the assumption that theGlobal
is an immutable Global data type.MaybeT Reader Global a
The code can be found on the f-readerT branch.
In order to combine it with the Maybe Monad, I opted for the
MaybeT
transformer monad. TheliftMaybe
function is responsible to liftMaybe
values into theMaybeT
monad and allows to combine the various search functions, which returnMaybe
values:https://github.com/tricktron/frege-lsp-server/blob/a7241931652560324f8d8a4d585f3219081ebe10/src/main/frege/ch/fhnw/thga/fregelanguageserver/hover/Hover.fr#L39-L40
https://github.com/tricktron/frege-lsp-server/blob/a7241931652560324f8d8a4d585f3219081ebe10/src/main/frege/ch/fhnw/thga/fregelanguageserver/hover/Hover.fr#L74-L84
getTypeOnHover
simpler. The Global data type is immutable as default. You could still run a computation in a different environment using thelocal
function. However, the user needs to actively do that.lift
to jump around the monad stack.ReaderT Maybe Global a
a.k.aKleisli Maybe Global a
The code can be found on the f-readerT-arrow branch.
This stack has the same pros and cons as the
MaybeT Reader Global a
approach. However, it has some subtle differences:Kleisli m a b
is an instance of theArrow
type class and the monad type class in Frege. This is a major difference to Haskell where theReaderT
is not anArrow
instance. According to the Haskell Typeclassopedia anArrow
and aMonad
is not the same butMonad
andArrowApply
are the same.I have never used the
Arrow
type class, so the following may be completely wrong and inaccurate:Since
Kleisli
is not an instance ofMonadTrans
we cannot use the standardlift
function, e.g:In Haskell this works because there is a MonadTrans instance of
ReaderT
. I did not manage to write aMonadTrans (ReaderT)
instance in Frege. Instead I wrote another helper functionliftKleisli
:https://github.com/tricktron/frege-lsp-server/blob/7f790e28a9a9af3f1d4e5ee3b884250d94fd1fd0/src/main/frege/ch/fhnw/thga/fregelanguageserver/hover/Hover.fr#L34-L35
The high-level
getTypeOnHover
function then looks like this:https://github.com/tricktron/frege-lsp-server/blob/7f790e28a9a9af3f1d4e5ee3b884250d94fd1fd0/src/main/frege/ch/fhnw/thga/fregelanguageserver/hover/Hover.fr#L65-L75
Instead of
lift
I used thearr
function to lift a function intoKleisli m
. This has the advantage that I can keep thegetSymbolType
function even simpler without making it aReader
:Using Arrow with Kleisli: https://github.com/tricktron/frege-lsp-server/blob/7f790e28a9a9af3f1d4e5ee3b884250d94fd1fd0/src/main/frege/ch/fhnw/thga/fregelanguageserver/hover/Hover.fr#L37-L38
Vs. Using Monad with MaybeT: https://github.com/tricktron/frege-lsp-server/blob/a7241931652560324f8d8a4d585f3219081ebe10/src/main/frege/ch/fhnw/thga/fregelanguageserver/hover/Hover.fr#L42-L45