Hi MarLinn!
In my use case the type collision is definitely much less likely to happen, that is i often want to compose different effects like logger, sql and network ,etc. without Has class, i will have a hard time trying to compose `Reader Logger ()` and `Reader (Logger, HttpClient) ()`, since the concrete type can't be unified.
If i need two different Logger in environment, i still can do it without Tagged, i can define following newtypes in library site:
newtype StdLogger = StdLogger Logger
newtype FileLogger = FileLogger Logger
librarySite :: (Has StdLogger r, Has FileLogger r, MonadReader r m) => m ()
librarySite = do ...
stdLogger :: StdLogger <- asks get
logWith stdLogger
...
fileLogger :: FileLogger <- asks get
logWith fileLogger
...
And in application site i should supply a (StdLogger log1, FileLogger log2, ...).
Does above example illustrate my use case to you?
Cheers~
Winter
Which brings us
back to fclabels I suppose.
Can you elaborate
this? I haven’t fully understand what is “incorporate the tag
in the class from the start” . Thanks you.
Suppose you have the original definitions
class Has a t where
get :: t -> a
instance Has a (a, b) where
get (a, _) = a
instance Has b (a, b) where
get (_, b) = b
This creates a conflict if you use an
(Int,Int) tuple
because there are either no definitions or two conflicting
definitions for
get.
As a solution you propose something along the lines of
Has (Tagged “GetGetsFirst” a) (a,b)
All I'm saying is that it seems useful or even
necessary for sanity to combine Has and Tagged so that you can write
Has “fst” a (a,b)
The implementation should be something simple like
class (KnownSymbol label) =>
Has label part whole | whole,label -> part where
get :: Proxy label -> whole -> part
-- 'Proxy label' is necessary because 'whole' and 'part' alone
are not sufficient to determine the label. See (Int,Int).
The obvious downside is that it doesn't
make as much sense to have such a class now. I must admit I'm
not too familiar with the alternatives, so I can't really
compare it. But this was just a flaw I saw. Hope this cleared up
what I meant.
Cheers,
MarLinn
1. Yes, it’s similar
to OverloadedRecordFields but doesn’t force you to
use a label, and you may use Tagged to label a field
if you want.
2. Yes, but again,
you can use Tagged to allow same type in different
disguise.
I can see a potential problem because you can't hide
instances. Once you define a Has-relationship, you can't
cheaply change it. That could lead to conflicts, unless
you hack around it with orphaned instances in a separate
module. But you say you want to solve conflicts with
tagging – so it would be reasonable to incorporate the tag
in the class from the start. Which brings us back to
fclabels I suppose.