Hi all, sorry for the bad title, I was unable to finde a better one.
I have problems making an idea work which I think should be possible, but maybe my mental model of types, type classes, Haskell or GHC is wrong.
Something that works
I have a type class HasText a
which says that Text
can be extracted from an a
, a type class Sections a b
which says that a section list of b
s can be extracted from a
:
class HasText a where
text :: a -> Text
-- MultiParamTypeClasses enabled
class Sections a b where
sections :: a -> [b]
and these trivial instances:
newtype PlainText = PT {plainText :: Text}
newtype SectionText = ST {textSections :: [PlainText]}
instance HasText PlainText where
text = plainText
instance Sections SectionText PlainText where
sections = textSections
I’d like to have a HasText
instance for SectionText
too, by external concatenation:
instance Semigroup PlainText where
pt1 <> pt2 = PT $ plainText pt1 <> plainText pt2
instance Monoid PlainText where
mempty = PT empty
instance HasText SectionText where
text = text . mconcat . (sections :: SectionText -> [PlainText])
This does the right thing™:
λ> text $ ST $ PT . pack <$> Prelude.words "foo bar baz"
"foobarbaz"
What I would like to have
What happens with other HasText
and Sections
instances? I thought I would be able to define a generalized HasText
for everything that has Sections
with HasText
and Monoid
:
instance (Sections a b, HasText b, Monoid b) => HasText a where
text = text . mconcat . (sections :: a -> [b])
How it fails
HLS first tells me to enable FlexibleInstances
, UndecidableInstances
, AllowAmbiguousTypes
and finally tells me
• Could not deduce (Sections a1 b1)
arising from a use of ‘sections’
from the context: (Sections a b, HasText b, Monoid b)
bound by the instance declaration
at HasText.hs:33:10-57
Possible fix:
add (Sections a1 b1) to the context of
an expression type signature:
forall a1 b1. a1 -> [b1]
• In the second argument of ‘(.)’, namely ‘(sections :: a -> [b])’
In the second argument of ‘(.)’, namely
‘mconcat . (sections :: a -> [b])’
In the expression: text . mconcat . (sections :: a -> [b])
I don’t understand the error neither the possible fix. Can someone explain this to me? Thank you very much!