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



On 22 Nov 2016, at 21:48, MarLinn <monkleyon@googlemail.com> wrote:

 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

Does this differ significantly from fclabels or the upcoming OverloadedRecordFields extension? (Aside from being purely type driven, which has problems in your example if you compose a second Int into it.)
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.