Monoid Instance
Hi all!
I need some guidance with Monoids. Help will be highly appreciated!
I had some code that I decided to refactor in Haskell fashion. I have a data structure:
data TwoFungiblesAndWitness = TwoFungiblesAndWitness with
f1 : FungibleImplementation.Fungible
f2 : FungibleImplementation.Fungible
witness: Party
And I have a list of functions that return Bool for this type:
isWitnessOwner: TwoFungiblesAndWitness -> Bool
isWitnessOwner TwoFungiblesAndWitness{ f1, f2, witness } = f1.account.owner == witness && f2.account.owner == witness
isSameAccount: TwoFungiblesAndWitness -> Bool
isSameAccount TwoFungiblesAndWitness{ f1, f2 } = f1.account == f2.account
isSameInstrument: TwoFungiblesAndWitness -> Bool
isSameInstrument TwoFungiblesAndWitness{ f1, f2 } = f1.instrument == f2.instrument
Now I want to pass my data through this list and return True only if all functions return True.
At the current moment, I do it like this:
isMergeable twoFungiblesAndWitness = all ((==True) . ($ twoFungiblesAndWitness)) [isWitnessOwner, isSameAccount, isSameInstrument]
And this is fine. But I want to add foldMap to my arsenal. So after learning I came up with this:
isMergeable = getAll . foldMap (All .) predicates
where predicates = [isWitnessOwner, isSameAccount, isSameInstrument]
I get an error here:
No instance for (Monoid (TwoFungiblesAndWitness -> All))
arising from a use of ‘foldMap’
How can I implement such an instance? As I understand I need to tell the compiler how to act with a list of functions, how concat results, etc…
I tried
instance Monoid (TwoFungiblesAndWitness -> All) where
mempty _ = All True
mappend
But I do not feel confident about what I should do here.
Thanks!
I think this is a case where making it more generic actually makes things a bit easier to understand: The Monoid instance we’re looking for here is Monoid b => Monoid (a -> b) so if the result type is a Monoid, the function is also a monoid. Looking at this we can also see that we need to combine the results. We can do that by just applying both functions to the same argument and then combining the results:
instance Semigroup b => Semigroup (a -> b) where
f <> g = \x -> f x <> g x
instance Monoid b => Monoid (a -> b) where
mempty = const mempty
instance Semigroup b => Semigroup (a -> b) where f <> g = \x -> f x <> g x instance Monoid b => Monoid (a -> b) where mempty = const mempty
Cool! Thanks!
This is the default Monoid implementation for any type, right? Can I think about it this way?
Since I didn’t specify any specific type, just added this code to the file and that’s it
I’d call it a “generic implementation”. default usually implies that you might overwrite it for some times. You wouldn’t really do that here usually.